mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[d3d12,metal,gl] add support for rendering to slices of 3D textures
This commit is contained in:
parent
15477b84a9
commit
d714e3d95a
@ -2,7 +2,7 @@ use wgpu::{
|
|||||||
util::{BufferInitDescriptor, DeviceExt},
|
util::{BufferInitDescriptor, DeviceExt},
|
||||||
vertex_attr_array,
|
vertex_attr_array,
|
||||||
};
|
};
|
||||||
use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext};
|
use wgpu_test::{gpu_test, FailureCase, GpuTestConfiguration, TestParameters, TestingContext};
|
||||||
|
|
||||||
#[gpu_test]
|
#[gpu_test]
|
||||||
static DRAW_TO_2D_VIEW: GpuTestConfiguration = GpuTestConfiguration::new()
|
static DRAW_TO_2D_VIEW: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
@ -233,3 +233,188 @@ async fn run_test(
|
|||||||
let succeeded = data.iter().all(|b| *b == u8::MAX);
|
let succeeded = data.iter().all(|b| *b == u8::MAX);
|
||||||
assert!(succeeded);
|
assert!(succeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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)),
|
||||||
|
)
|
||||||
|
.run_async(run_test_3d);
|
||||||
|
|
||||||
|
async fn run_test_3d(ctx: TestingContext) {
|
||||||
|
let vertex_buffer_content: &[f32; 12] = &[
|
||||||
|
// Triangle 1
|
||||||
|
-1.0, -1.0, // Bottom left
|
||||||
|
1.0, 1.0, // Top right
|
||||||
|
-1.0, 1.0, // Top left
|
||||||
|
// Triangle 2
|
||||||
|
-1.0, -1.0, // Bottom left
|
||||||
|
1.0, -1.0, // Bottom right
|
||||||
|
1.0, 1.0, // Top right
|
||||||
|
];
|
||||||
|
let vertex_buffer = ctx.device.create_buffer_init(&BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
contents: bytemuck::cast_slice(vertex_buffer_content),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
let shader_src = "
|
||||||
|
@vertex
|
||||||
|
fn vs_main(@location(0) position: vec2f) -> @builtin(position) vec4f {
|
||||||
|
return vec4f(position, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main() -> @location(0) vec4f {
|
||||||
|
return vec4f(1.0);
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
let shader = ctx
|
||||||
|
.device
|
||||||
|
.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(shader_src.into()),
|
||||||
|
});
|
||||||
|
|
||||||
|
let pipeline_desc = wgpu::RenderPipelineDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: 8,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &vertex_attr_array![0 => Float32x2],
|
||||||
|
}],
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("fs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: wgpu::TextureFormat::R8Unorm,
|
||||||
|
blend: None,
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
};
|
||||||
|
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||||
|
|
||||||
|
const SIZE: u32 = 512;
|
||||||
|
const DEPTH: u32 = 2;
|
||||||
|
const MIPS: u32 = 2;
|
||||||
|
const fn size_for_mips(mips: u32) -> u64 {
|
||||||
|
let mut out: u64 = 0;
|
||||||
|
let mut mip = 0;
|
||||||
|
while mip < mips {
|
||||||
|
let size = SIZE as u64 >> mip;
|
||||||
|
let z = DEPTH as u64 >> mip;
|
||||||
|
out += size * size * z;
|
||||||
|
|
||||||
|
mip += 1;
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
let out_texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: SIZE,
|
||||||
|
height: SIZE,
|
||||||
|
depth_or_array_layers: DEPTH,
|
||||||
|
},
|
||||||
|
mip_level_count: MIPS,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D3,
|
||||||
|
format: wgpu::TextureFormat::R8Unorm,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: size_for_mips(MIPS),
|
||||||
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
|
for mip in 0..MIPS {
|
||||||
|
let out_texture_view = out_texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
base_mip_level: mip,
|
||||||
|
mip_level_count: Some(1),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
for layer in 0..DEPTH >> mip {
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &out_texture_view,
|
||||||
|
depth_slice: Some(layer),
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
rpass.set_pipeline(&pipeline);
|
||||||
|
rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||||
|
rpass.draw(0..6, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for mip in 0..MIPS {
|
||||||
|
encoder.copy_texture_to_buffer(
|
||||||
|
wgpu::TexelCopyTextureInfo {
|
||||||
|
texture: &out_texture,
|
||||||
|
mip_level: mip,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
wgpu::TexelCopyBufferInfo {
|
||||||
|
buffer: &readback_buffer,
|
||||||
|
layout: wgpu::TexelCopyBufferLayout {
|
||||||
|
offset: size_for_mips(mip),
|
||||||
|
bytes_per_row: Some(SIZE >> mip),
|
||||||
|
rows_per_image: Some(SIZE >> mip),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: SIZE >> mip,
|
||||||
|
height: SIZE >> mip,
|
||||||
|
depth_or_array_layers: DEPTH >> mip,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
|
||||||
|
let slice = readback_buffer.slice(..);
|
||||||
|
slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||||
|
|
||||||
|
ctx.async_poll(wgpu::PollType::wait()).await.unwrap();
|
||||||
|
|
||||||
|
let data = slice.get_mapped_range();
|
||||||
|
let succeeded = data.iter().all(|b| *b == u8::MAX);
|
||||||
|
assert!(succeeded);
|
||||||
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use crate::command::{
|
|||||||
};
|
};
|
||||||
use crate::init_tracker::BufferInitTrackerAction;
|
use crate::init_tracker::BufferInitTrackerAction;
|
||||||
use crate::pipeline::{RenderPipeline, VertexStep};
|
use crate::pipeline::{RenderPipeline, VertexStep};
|
||||||
use crate::resource::InvalidResourceError;
|
use crate::resource::{InvalidResourceError, ResourceErrorIdent};
|
||||||
use crate::snatch::SnatchGuard;
|
use crate::snatch::SnatchGuard;
|
||||||
use crate::{
|
use crate::{
|
||||||
api_log,
|
api_log,
|
||||||
@ -621,6 +621,18 @@ pub enum ColorAttachmentError {
|
|||||||
TooMany { given: usize, limit: usize },
|
TooMany { given: usize, limit: usize },
|
||||||
#[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
|
#[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")]
|
||||||
TooManyBytesPerSample { total: u32, limit: u32 },
|
TooManyBytesPerSample { total: u32, limit: u32 },
|
||||||
|
#[error("Depth slice must be less than {limit} but is {given}")]
|
||||||
|
DepthSliceLimit { given: u32, limit: u32 },
|
||||||
|
#[error("Color attachment's view is 3D and requires depth slice to be provided")]
|
||||||
|
MissingDepthSlice,
|
||||||
|
#[error("Depth slice was provided but the color attachment's view is not 3D")]
|
||||||
|
UnneededDepthSlice,
|
||||||
|
#[error("{view}'s subresource at mip {mip_level} and depth/array layer {depth_or_array_layer} is already attached to this render pass")]
|
||||||
|
SubresourceOverlap {
|
||||||
|
view: ResourceErrorIdent,
|
||||||
|
mip_level: u32,
|
||||||
|
depth_or_array_layer: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
@ -1096,6 +1108,8 @@ impl<'d> RenderPassInfo<'d> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut attachment_set = crate::FastHashSet::default();
|
||||||
|
|
||||||
let mut color_attachments_hal =
|
let mut color_attachments_hal =
|
||||||
ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
|
ArrayVec::<Option<hal::ColorAttachment<_>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
|
||||||
for (index, attachment) in color_attachments.iter().enumerate() {
|
for (index, attachment) in color_attachments.iter().enumerate() {
|
||||||
@ -1126,6 +1140,71 @@ impl<'d> RenderPassInfo<'d> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if color_view.desc.dimension == TextureViewDimension::D3 {
|
||||||
|
if let Some(depth_slice) = at.depth_slice {
|
||||||
|
let mip = color_view.desc.range.base_mip_level;
|
||||||
|
let mip_size = color_view
|
||||||
|
.parent
|
||||||
|
.desc
|
||||||
|
.size
|
||||||
|
.mip_level_size(mip, color_view.parent.desc.dimension);
|
||||||
|
let limit = mip_size.depth_or_array_layers;
|
||||||
|
if depth_slice >= limit {
|
||||||
|
return Err(RenderPassErrorInner::ColorAttachment(
|
||||||
|
ColorAttachmentError::DepthSliceLimit {
|
||||||
|
given: depth_slice,
|
||||||
|
limit,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(RenderPassErrorInner::ColorAttachment(
|
||||||
|
ColorAttachmentError::MissingDepthSlice,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if at.depth_slice.is_some() {
|
||||||
|
return Err(RenderPassErrorInner::ColorAttachment(
|
||||||
|
ColorAttachmentError::UnneededDepthSlice,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_attachment_overlap(
|
||||||
|
attachment_set: &mut crate::FastHashSet<(crate::track::TrackerIndex, u32, u32)>,
|
||||||
|
view: &TextureView,
|
||||||
|
depth_slice: Option<u32>,
|
||||||
|
) -> Result<(), ColorAttachmentError> {
|
||||||
|
let mut insert = |slice| {
|
||||||
|
let mip_level = view.desc.range.base_mip_level;
|
||||||
|
if attachment_set.insert((view.tracking_data.tracker_index(), mip_level, slice))
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ColorAttachmentError::SubresourceOverlap {
|
||||||
|
view: view.error_ident(),
|
||||||
|
mip_level,
|
||||||
|
depth_or_array_layer: slice,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match view.desc.dimension {
|
||||||
|
TextureViewDimension::D2 => {
|
||||||
|
insert(view.desc.range.base_array_layer)?;
|
||||||
|
}
|
||||||
|
TextureViewDimension::D2Array => {
|
||||||
|
for layer in view.selector.layers.clone() {
|
||||||
|
insert(layer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextureViewDimension::D3 => {
|
||||||
|
insert(depth_slice.unwrap())?;
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
check_attachment_overlap(&mut attachment_set, color_view, at.depth_slice)?;
|
||||||
|
|
||||||
Self::add_pass_texture_init_actions(
|
Self::add_pass_texture_init_actions(
|
||||||
at.load_op,
|
at.load_op,
|
||||||
at.store_op,
|
at.store_op,
|
||||||
@ -1141,6 +1220,8 @@ impl<'d> RenderPassInfo<'d> {
|
|||||||
resolve_view.same_device(device)?;
|
resolve_view.same_device(device)?;
|
||||||
check_multiview(resolve_view)?;
|
check_multiview(resolve_view)?;
|
||||||
|
|
||||||
|
check_attachment_overlap(&mut attachment_set, resolve_view, None)?;
|
||||||
|
|
||||||
let resolve_location = AttachmentErrorLocation::Color {
|
let resolve_location = AttachmentErrorLocation::Color {
|
||||||
index,
|
index,
|
||||||
resolve: true,
|
resolve: true,
|
||||||
|
|||||||
@ -929,8 +929,11 @@ impl Device {
|
|||||||
desc.format,
|
desc.format,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// Renderable textures can only be 2D
|
|
||||||
if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
|
// 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(
|
return Err(CreateTextureError::InvalidDimensionUsages(
|
||||||
wgt::TextureUsages::RENDER_ATTACHMENT,
|
wgt::TextureUsages::RENDER_ATTACHMENT,
|
||||||
desc.dimension,
|
desc.dimension,
|
||||||
@ -948,6 +951,14 @@ impl Device {
|
|||||||
desc.format,
|
desc.format,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renderable textures can only be 2D or 3D
|
||||||
|
if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
|
||||||
|
return Err(CreateTextureError::InvalidDimensionUsages(
|
||||||
|
wgt::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
desc.dimension,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if desc.format.is_compressed() {
|
if desc.format.is_compressed() {
|
||||||
@ -1124,17 +1135,13 @@ impl Device {
|
|||||||
|
|
||||||
let clear_mode = if hal_usage
|
let clear_mode = if hal_usage
|
||||||
.intersects(wgt::TextureUses::DEPTH_STENCIL_WRITE | wgt::TextureUses::COLOR_TARGET)
|
.intersects(wgt::TextureUses::DEPTH_STENCIL_WRITE | wgt::TextureUses::COLOR_TARGET)
|
||||||
|
&& desc.dimension == wgt::TextureDimension::D2
|
||||||
{
|
{
|
||||||
let (is_color, usage) = if desc.format.is_depth_stencil_format() {
|
let (is_color, usage) = if desc.format.is_depth_stencil_format() {
|
||||||
(false, wgt::TextureUses::DEPTH_STENCIL_WRITE)
|
(false, wgt::TextureUses::DEPTH_STENCIL_WRITE)
|
||||||
} else {
|
} else {
|
||||||
(true, wgt::TextureUses::COLOR_TARGET)
|
(true, wgt::TextureUses::COLOR_TARGET)
|
||||||
};
|
};
|
||||||
let dimension = match desc.dimension {
|
|
||||||
wgt::TextureDimension::D1 => TextureViewDimension::D1,
|
|
||||||
wgt::TextureDimension::D2 => TextureViewDimension::D2,
|
|
||||||
wgt::TextureDimension::D3 => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let clear_label = hal_label(
|
let clear_label = hal_label(
|
||||||
Some("(wgpu internal) clear texture view"),
|
Some("(wgpu internal) clear texture view"),
|
||||||
@ -1149,7 +1156,7 @@ impl Device {
|
|||||||
let desc = hal::TextureViewDescriptor {
|
let desc = hal::TextureViewDescriptor {
|
||||||
label: clear_label,
|
label: clear_label,
|
||||||
format: $format,
|
format: $format,
|
||||||
dimension,
|
dimension: TextureViewDimension::D2,
|
||||||
usage,
|
usage,
|
||||||
range: wgt::ImageSubresourceRange {
|
range: wgt::ImageSubresourceRange {
|
||||||
aspect: $aspect,
|
aspect: $aspect,
|
||||||
@ -1420,9 +1427,12 @@ impl Device {
|
|||||||
break 'error Err(TextureViewNotRenderableReason::Usage(resolved_usage));
|
break 'error Err(TextureViewNotRenderableReason::Usage(resolved_usage));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(resolved_dimension == TextureViewDimension::D2
|
let allowed_view_dimensions = [
|
||||||
|| resolved_dimension == TextureViewDimension::D2Array)
|
TextureViewDimension::D2,
|
||||||
{
|
TextureViewDimension::D2Array,
|
||||||
|
TextureViewDimension::D3,
|
||||||
|
];
|
||||||
|
if !allowed_view_dimensions.contains(&resolved_dimension) {
|
||||||
break 'error Err(TextureViewNotRenderableReason::Dimension(
|
break 'error Err(TextureViewNotRenderableReason::Dimension(
|
||||||
resolved_dimension,
|
resolved_dimension,
|
||||||
));
|
));
|
||||||
|
|||||||
@ -73,6 +73,13 @@ impl Drop for super::CommandEncoder {
|
|||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
use crate::CommandEncoder;
|
use crate::CommandEncoder;
|
||||||
unsafe { self.discard_encoding() }
|
unsafe { self.discard_encoding() }
|
||||||
|
|
||||||
|
let mut rtv_pool = self.rtv_pool.lock();
|
||||||
|
for handle in self.temp_rtv_handles.drain(..) {
|
||||||
|
rtv_pool.free_handle(handle);
|
||||||
|
}
|
||||||
|
drop(rtv_pool);
|
||||||
|
|
||||||
self.counters.command_encoders.sub(1);
|
self.counters.command_encoders.sub(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -762,13 +769,39 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
|
|
||||||
let mut color_views =
|
let mut color_views =
|
||||||
[Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; crate::MAX_COLOR_ATTACHMENTS];
|
[Direct3D12::D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 }; crate::MAX_COLOR_ATTACHMENTS];
|
||||||
|
let mut rtv_pool = self.rtv_pool.lock();
|
||||||
for (rtv, cat) in color_views.iter_mut().zip(desc.color_attachments.iter()) {
|
for (rtv, cat) in color_views.iter_mut().zip(desc.color_attachments.iter()) {
|
||||||
if let Some(cat) = cat.as_ref() {
|
if let Some(cat) = cat.as_ref() {
|
||||||
*rtv = cat.target.view.handle_rtv.unwrap().raw;
|
if cat.target.view.dimension == wgt::TextureViewDimension::D3 {
|
||||||
|
let desc = Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC {
|
||||||
|
Format: cat.target.view.raw_format,
|
||||||
|
ViewDimension: Direct3D12::D3D12_RTV_DIMENSION_TEXTURE3D,
|
||||||
|
Anonymous: Direct3D12::D3D12_RENDER_TARGET_VIEW_DESC_0 {
|
||||||
|
Texture3D: Direct3D12::D3D12_TEX3D_RTV {
|
||||||
|
MipSlice: cat.target.view.mip_slice,
|
||||||
|
FirstWSlice: cat.depth_slice.unwrap(),
|
||||||
|
WSize: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let handle = rtv_pool.alloc_handle()?;
|
||||||
|
unsafe {
|
||||||
|
self.device.CreateRenderTargetView(
|
||||||
|
&cat.target.view.texture,
|
||||||
|
Some(&desc),
|
||||||
|
handle.raw,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
*rtv = handle.raw;
|
||||||
|
self.temp_rtv_handles.push(handle);
|
||||||
|
} else {
|
||||||
|
*rtv = cat.target.view.handle_rtv.unwrap().raw;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
*rtv = self.null_rtv_handle.raw;
|
*rtv = self.null_rtv_handle.raw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(rtv_pool);
|
||||||
|
|
||||||
let ds_view = desc.depth_stencil_attachment.as_ref().map(|ds| {
|
let ds_view = desc.depth_stencil_attachment.as_ref().map(|ds| {
|
||||||
if ds.target.usage == wgt::TextureUses::DEPTH_STENCIL_WRITE {
|
if ds.target.usage == wgt::TextureUses::DEPTH_STENCIL_WRITE {
|
||||||
@ -803,8 +836,11 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
}
|
}
|
||||||
if let Some(ref target) = cat.resolve_target {
|
if let Some(ref target) = cat.resolve_target {
|
||||||
self.pass.resolves.push(super::PassResolve {
|
self.pass.resolves.push(super::PassResolve {
|
||||||
src: cat.target.view.target_base.clone(),
|
src: (
|
||||||
dst: target.view.target_base.clone(),
|
cat.target.view.texture.clone(),
|
||||||
|
cat.target.view.subresource_index,
|
||||||
|
),
|
||||||
|
dst: (target.view.texture.clone(), target.view.subresource_index),
|
||||||
format: target.view.raw_format,
|
format: target.view.raw_format,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -188,7 +188,7 @@ impl super::Device {
|
|||||||
},
|
},
|
||||||
features,
|
features,
|
||||||
shared: Arc::new(shared),
|
shared: Arc::new(shared),
|
||||||
rtv_pool: Mutex::new(rtv_pool),
|
rtv_pool: Arc::new(Mutex::new(rtv_pool)),
|
||||||
dsv_pool: Mutex::new(descriptor::CpuPool::new(
|
dsv_pool: Mutex::new(descriptor::CpuPool::new(
|
||||||
raw.clone(),
|
raw.clone(),
|
||||||
Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
|
Direct3D12::D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
|
||||||
@ -539,10 +539,14 @@ impl crate::Device for super::Device {
|
|||||||
Ok(super::TextureView {
|
Ok(super::TextureView {
|
||||||
raw_format: view_desc.rtv_dsv_format,
|
raw_format: view_desc.rtv_dsv_format,
|
||||||
aspects: view_desc.aspects,
|
aspects: view_desc.aspects,
|
||||||
target_base: (
|
dimension: desc.dimension,
|
||||||
texture.resource.clone(),
|
texture: texture.resource.clone(),
|
||||||
texture.calc_subresource(desc.range.base_mip_level, desc.range.base_array_layer, 0),
|
subresource_index: texture.calc_subresource(
|
||||||
|
desc.range.base_mip_level,
|
||||||
|
desc.range.base_array_layer,
|
||||||
|
0,
|
||||||
),
|
),
|
||||||
|
mip_slice: desc.range.base_mip_level,
|
||||||
handle_srv: if desc.usage.intersects(wgt::TextureUses::RESOURCE) {
|
handle_srv: if desc.usage.intersects(wgt::TextureUses::RESOURCE) {
|
||||||
match unsafe { view_desc.to_srv() } {
|
match unsafe { view_desc.to_srv() } {
|
||||||
Some(raw_desc) => {
|
Some(raw_desc) => {
|
||||||
@ -584,7 +588,10 @@ impl crate::Device for super::Device {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
handle_rtv: if desc.usage.intersects(wgt::TextureUses::COLOR_TARGET) {
|
handle_rtv: if desc.usage.intersects(wgt::TextureUses::COLOR_TARGET)
|
||||||
|
&& desc.dimension != wgt::TextureViewDimension::D3
|
||||||
|
// 3D RTVs must be created in the render pass
|
||||||
|
{
|
||||||
let raw_desc = unsafe { view_desc.to_rtv() };
|
let raw_desc = unsafe { view_desc.to_rtv() };
|
||||||
let handle = self.rtv_pool.lock().alloc_handle()?;
|
let handle = self.rtv_pool.lock().alloc_handle()?;
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -725,6 +732,8 @@ impl crate::Device for super::Device {
|
|||||||
device: self.raw.clone(),
|
device: self.raw.clone(),
|
||||||
shared: Arc::clone(&self.shared),
|
shared: Arc::clone(&self.shared),
|
||||||
mem_allocator: self.mem_allocator.clone(),
|
mem_allocator: self.mem_allocator.clone(),
|
||||||
|
rtv_pool: Arc::clone(&self.rtv_pool),
|
||||||
|
temp_rtv_handles: Vec::new(),
|
||||||
null_rtv_handle: self.null_rtv_handle,
|
null_rtv_handle: self.null_rtv_handle,
|
||||||
list: None,
|
list: None,
|
||||||
free_lists: Vec::new(),
|
free_lists: Vec::new(),
|
||||||
|
|||||||
@ -646,7 +646,7 @@ pub struct Device {
|
|||||||
features: wgt::Features,
|
features: wgt::Features,
|
||||||
shared: Arc<DeviceShared>,
|
shared: Arc<DeviceShared>,
|
||||||
// CPU only pools
|
// CPU only pools
|
||||||
rtv_pool: Mutex<descriptor::CpuPool>,
|
rtv_pool: Arc<Mutex<descriptor::CpuPool>>,
|
||||||
dsv_pool: Mutex<descriptor::CpuPool>,
|
dsv_pool: Mutex<descriptor::CpuPool>,
|
||||||
srv_uav_pool: Mutex<descriptor::CpuPool>,
|
srv_uav_pool: Mutex<descriptor::CpuPool>,
|
||||||
// library
|
// library
|
||||||
@ -798,6 +798,9 @@ pub struct CommandEncoder {
|
|||||||
shared: Arc<DeviceShared>,
|
shared: Arc<DeviceShared>,
|
||||||
mem_allocator: Allocator,
|
mem_allocator: Allocator,
|
||||||
|
|
||||||
|
rtv_pool: Arc<Mutex<descriptor::CpuPool>>,
|
||||||
|
temp_rtv_handles: Vec<descriptor::Handle>,
|
||||||
|
|
||||||
null_rtv_handle: descriptor::Handle,
|
null_rtv_handle: descriptor::Handle,
|
||||||
list: Option<Direct3D12::ID3D12GraphicsCommandList>,
|
list: Option<Direct3D12::ID3D12GraphicsCommandList>,
|
||||||
free_lists: Vec<Direct3D12::ID3D12GraphicsCommandList>,
|
free_lists: Vec<Direct3D12::ID3D12GraphicsCommandList>,
|
||||||
@ -918,8 +921,10 @@ impl Texture {
|
|||||||
pub struct TextureView {
|
pub struct TextureView {
|
||||||
raw_format: Dxgi::Common::DXGI_FORMAT,
|
raw_format: Dxgi::Common::DXGI_FORMAT,
|
||||||
aspects: crate::FormatAspects,
|
aspects: crate::FormatAspects,
|
||||||
/// only used by resolve
|
dimension: wgt::TextureViewDimension,
|
||||||
target_base: (Direct3D12::ID3D12Resource, u32),
|
texture: Direct3D12::ID3D12Resource,
|
||||||
|
subresource_index: u32,
|
||||||
|
mip_slice: u32,
|
||||||
handle_srv: Option<descriptor::Handle>,
|
handle_srv: Option<descriptor::Handle>,
|
||||||
handle_uav: Option<descriptor::Handle>,
|
handle_uav: Option<descriptor::Handle>,
|
||||||
handle_rtv: Option<descriptor::Handle>,
|
handle_rtv: Option<descriptor::Handle>,
|
||||||
|
|||||||
@ -250,16 +250,10 @@ impl ViewDescriptor {
|
|||||||
PlaneSlice: aspects_to_plane(self.aspects),
|
PlaneSlice: aspects_to_plane(self.aspects),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wgt::TextureViewDimension::D3 => {
|
wgt::TextureViewDimension::D3
|
||||||
desc.ViewDimension = Direct3D12::D3D12_RTV_DIMENSION_TEXTURE3D;
|
| wgt::TextureViewDimension::Cube
|
||||||
desc.Anonymous.Texture3D = Direct3D12::D3D12_TEX3D_RTV {
|
| wgt::TextureViewDimension::CubeArray => {
|
||||||
MipSlice: self.mip_level_base,
|
panic!("Unable to view texture as cube or 3D RTV")
|
||||||
FirstWSlice: self.array_layer_base,
|
|
||||||
WSize: self.array_layer_count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wgt::TextureViewDimension::Cube | wgt::TextureViewDimension::CubeArray => {
|
|
||||||
panic!("Unable to view texture as cube RTV")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +331,7 @@ impl ViewDescriptor {
|
|||||||
wgt::TextureViewDimension::D3
|
wgt::TextureViewDimension::D3
|
||||||
| wgt::TextureViewDimension::Cube
|
| wgt::TextureViewDimension::Cube
|
||||||
| wgt::TextureViewDimension::CubeArray => {
|
| wgt::TextureViewDimension::CubeArray => {
|
||||||
panic!("Unable to view texture as cube or 3D RTV")
|
panic!("Unable to view texture as cube or 3D DSV")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -557,6 +557,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
self.cmd_buffer.commands.push(C::BindAttachment {
|
self.cmd_buffer.commands.push(C::BindAttachment {
|
||||||
attachment,
|
attachment,
|
||||||
view: cat.target.view.clone(),
|
view: cat.target.view.clone(),
|
||||||
|
depth_slice: cat.depth_slice,
|
||||||
});
|
});
|
||||||
if let Some(ref rat) = cat.resolve_target {
|
if let Some(ref rat) = cat.resolve_target {
|
||||||
self.state
|
self.state
|
||||||
@ -578,6 +579,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
self.cmd_buffer.commands.push(C::BindAttachment {
|
self.cmd_buffer.commands.push(C::BindAttachment {
|
||||||
attachment,
|
attachment,
|
||||||
view: dsat.target.view.clone(),
|
view: dsat.target.view.clone(),
|
||||||
|
depth_slice: None,
|
||||||
});
|
});
|
||||||
if aspects.contains(crate::FormatAspects::DEPTH)
|
if aspects.contains(crate::FormatAspects::DEPTH)
|
||||||
&& !dsat.depth_ops.contains(crate::AttachmentOps::STORE)
|
&& !dsat.depth_ops.contains(crate::AttachmentOps::STORE)
|
||||||
|
|||||||
@ -902,6 +902,7 @@ enum Command {
|
|||||||
BindAttachment {
|
BindAttachment {
|
||||||
attachment: u32,
|
attachment: u32,
|
||||||
view: TextureView,
|
view: TextureView,
|
||||||
|
depth_slice: Option<u32>,
|
||||||
},
|
},
|
||||||
ResolveAttachment {
|
ResolveAttachment {
|
||||||
attachment: u32,
|
attachment: u32,
|
||||||
|
|||||||
@ -98,6 +98,7 @@ impl super::Queue {
|
|||||||
fbo_target: u32,
|
fbo_target: u32,
|
||||||
attachment: u32,
|
attachment: u32,
|
||||||
view: &super::TextureView,
|
view: &super::TextureView,
|
||||||
|
depth_slice: Option<u32>,
|
||||||
) {
|
) {
|
||||||
match view.inner {
|
match view.inner {
|
||||||
super::TextureInner::Renderbuffer { raw } => {
|
super::TextureInner::Renderbuffer { raw } => {
|
||||||
@ -126,13 +127,18 @@ impl super::Queue {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
} else if is_layered_target(target) {
|
} else if is_layered_target(target) {
|
||||||
|
let layer = if target == glow::TEXTURE_3D {
|
||||||
|
depth_slice.unwrap() as i32
|
||||||
|
} else {
|
||||||
|
view.array_layers.start as i32
|
||||||
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.framebuffer_texture_layer(
|
gl.framebuffer_texture_layer(
|
||||||
fbo_target,
|
fbo_target,
|
||||||
attachment,
|
attachment,
|
||||||
Some(raw),
|
Some(raw),
|
||||||
view.mip_levels.start as i32,
|
view.mip_levels.start as i32,
|
||||||
view.array_layers.start as i32,
|
layer,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -1096,8 +1102,11 @@ impl super::Queue {
|
|||||||
C::BindAttachment {
|
C::BindAttachment {
|
||||||
attachment,
|
attachment,
|
||||||
ref view,
|
ref view,
|
||||||
|
depth_slice,
|
||||||
} => {
|
} => {
|
||||||
unsafe { self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view) };
|
unsafe {
|
||||||
|
self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view, depth_slice)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
C::ResolveAttachment {
|
C::ResolveAttachment {
|
||||||
attachment,
|
attachment,
|
||||||
@ -1108,7 +1117,13 @@ impl super::Queue {
|
|||||||
unsafe { gl.read_buffer(attachment) };
|
unsafe { gl.read_buffer(attachment) };
|
||||||
unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
|
unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)) };
|
||||||
unsafe {
|
unsafe {
|
||||||
self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst)
|
self.set_attachment(
|
||||||
|
gl,
|
||||||
|
glow::DRAW_FRAMEBUFFER,
|
||||||
|
glow::COLOR_ATTACHMENT0,
|
||||||
|
dst,
|
||||||
|
None,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.blit_framebuffer(
|
gl.blit_framebuffer(
|
||||||
|
|||||||
@ -532,6 +532,9 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
if let Some(at) = at.as_ref() {
|
if let Some(at) = at.as_ref() {
|
||||||
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
|
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
|
||||||
at_descriptor.set_texture(Some(&at.target.view.raw));
|
at_descriptor.set_texture(Some(&at.target.view.raw));
|
||||||
|
if let Some(depth_slice) = at.depth_slice {
|
||||||
|
at_descriptor.set_depth_plane(depth_slice as u64);
|
||||||
|
}
|
||||||
if let Some(ref resolve) = at.resolve_target {
|
if let Some(ref resolve) = at.resolve_target {
|
||||||
//Note: the selection of levels and slices is already handled by `TextureView`
|
//Note: the selection of levels and slices is already handled by `TextureView`
|
||||||
at_descriptor.set_resolve_texture(Some(&resolve.view.raw));
|
at_descriptor.set_resolve_texture(Some(&resolve.view.raw));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user