[vk] add support for rendering to slices of 3D textures

This commit is contained in:
teoxoy 2025-04-23 16:37:47 +02:00 committed by Teodor Tanasoaia
parent f728a92366
commit d14849df48
5 changed files with 68 additions and 20 deletions

View File

@ -2,7 +2,7 @@ use wgpu::{
util::{BufferInitDescriptor, DeviceExt},
vertex_attr_array,
};
use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext};
use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext};
#[gpu_test]
static DRAW_TO_2D_VIEW: GpuTestConfiguration = GpuTestConfiguration::new()
@ -236,14 +236,10 @@ async fn run_test(
#[gpu_test]
static DRAW_TO_3D_VIEW: GpuTestConfiguration = GpuTestConfiguration::new()
.parameters(
TestParameters::default()
.limits(wgpu::Limits {
max_texture_dimension_3d: 512,
..wgpu::Limits::downlevel_webgl2_defaults()
})
.skip(FailureCase::backend(wgpu::Backends::VULKAN)),
)
.parameters(TestParameters::default().limits(wgpu::Limits {
max_texture_dimension_3d: 512,
..wgpu::Limits::downlevel_webgl2_defaults()
}))
.run_async(run_test_3d);
async fn run_test_3d(ctx: TestingContext) {

View File

@ -929,16 +929,6 @@ impl Device {
desc.format,
));
}
// Renderable textures can only be 2D on Vulkan (until we implement 3D support)
if self.backend() == wgt::Backend::Vulkan
&& desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT)
{
return Err(CreateTextureError::InvalidDimensionUsages(
wgt::TextureUsages::RENDER_ATTACHMENT,
desc.dimension,
));
}
}
if desc.dimension != wgt::TextureDimension::D2

View File

@ -71,6 +71,31 @@ impl super::CommandEncoder {
}
})
}
fn make_temp_texture_view(
&mut self,
key: super::TempTextureViewKey,
) -> Result<vk::ImageView, crate::DeviceError> {
Ok(match self.temp_texture_views.entry(key) {
Entry::Occupied(e) => *e.get(),
Entry::Vacant(e) => {
let vk_info = vk::ImageViewCreateInfo::default()
.image(e.key().texture)
.view_type(vk::ImageViewType::TYPE_2D)
.format(e.key().format)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: e.key().mip_level,
level_count: 1,
base_array_layer: e.key().depth_slice,
layer_count: 1,
});
let raw = unsafe { self.device.raw.create_image_view(&vk_info, None) }
.map_err(super::map_host_device_oom_and_ioca_err)?;
*e.insert(raw)
}
})
}
}
impl crate::CommandEncoder for super::CommandEncoder {
@ -747,6 +772,18 @@ impl crate::CommandEncoder for super::CommandEncoder {
for cat in desc.color_attachments {
if let Some(cat) = cat.as_ref() {
let color_view = if cat.target.view.dimension == wgt::TextureViewDimension::D3 {
let key = super::TempTextureViewKey {
texture: cat.target.view.raw_texture,
format: cat.target.view.raw_format,
mip_level: cat.target.view.base_mip_level,
depth_slice: cat.depth_slice.unwrap(),
};
self.make_temp_texture_view(key)?
} else {
cat.target.view.raw
};
vk_clear_values.push(vk::ClearValue {
color: unsafe { cat.make_vk_clear_color() },
});
@ -759,7 +796,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
};
rp_key.colors.push(Some(color));
fb_key.attachments.push(cat.target.view.raw);
fb_key.attachments.push(color_view);
if let Some(ref at) = cat.resolve_target {
vk_clear_values.push(unsafe { mem::zeroed() });
fb_key.attachments.push(at.view.raw);

View File

@ -640,6 +640,11 @@ impl super::Device {
let copy_size = desc.copy_extent();
let mut raw_flags = vk::ImageCreateFlags::empty();
if desc.dimension == wgt::TextureDimension::D3
&& desc.usage.contains(wgt::TextureUses::COLOR_TARGET)
{
raw_flags |= vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE;
}
if desc.is_cube_compatible() {
raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE;
}
@ -1287,10 +1292,13 @@ impl crate::Device for super::Device {
self.counters.texture_views.add(1);
Ok(super::TextureView {
raw_texture: texture.raw,
raw,
layers,
format: desc.format,
raw_format,
base_mip_level: desc.range.base_mip_level,
dimension: desc.dimension,
})
}
unsafe fn destroy_texture_view(&self, view: super::TextureView) {
@ -1387,6 +1395,7 @@ impl crate::Device for super::Device {
rpass_debug_marker_active: false,
end_of_pass_timer_query: None,
framebuffers: Default::default(),
temp_texture_views: Default::default(),
counters: Arc::clone(&self.counters),
})
}

View File

@ -790,10 +790,13 @@ impl Texture {
#[derive(Debug)]
pub struct TextureView {
raw_texture: vk::Image,
raw: vk::ImageView,
layers: NonZeroU32,
format: wgt::TextureFormat,
raw_format: vk::Format,
base_mip_level: u32,
dimension: wgt::TextureViewDimension,
}
impl crate::DynTextureView for TextureView {}
@ -871,6 +874,14 @@ struct FramebufferKey {
extent: wgt::Extent3d,
}
#[derive(Clone, Eq, Hash, PartialEq)]
struct TempTextureViewKey {
texture: vk::Image,
format: vk::Format,
mip_level: u32,
depth_slice: u32,
}
pub struct CommandEncoder {
raw: vk::CommandPool,
device: Arc<DeviceShared>,
@ -908,6 +919,7 @@ pub struct CommandEncoder {
end_of_pass_timer_query: Option<(vk::QueryPool, u32)>,
framebuffers: FastHashMap<FramebufferKey, vk::Framebuffer>,
temp_texture_views: FastHashMap<TempTextureViewKey, vk::ImageView>,
counters: Arc<wgt::HalCounters>,
}
@ -935,6 +947,10 @@ impl Drop for CommandEncoder {
unsafe { self.device.raw.destroy_framebuffer(fb, None) };
}
for (_, view) in self.temp_texture_views.drain() {
unsafe { self.device.raw.destroy_image_view(view, None) };
}
self.counters.command_encoders.sub(1);
}
}