mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Multiview on DX12 (#8495)
Co-authored-by: Andreas Reich <r_andreas2@web.de>
This commit is contained in:
parent
c78f944f2f
commit
05369a6b83
@ -82,7 +82,7 @@ can use this feature.
|
||||
|
||||
Multiview is also called view instancing in DX12 land or vertex amplification in Metal land.
|
||||
|
||||
Multiview has been reworked, adding support for Metal, and adding testing and validation to wgpu itself.
|
||||
Multiview has been reworked, adding support for Metal and DX12, and adding testing and validation to wgpu itself.
|
||||
This change also introduces a view bitmask, a new field in `RenderPassDescriptor` that allows a render pass to render to multiple non-adjacent layers
|
||||
when using the `SELECTIVE_MULTIVIEW` feature. Note that this also influences apps that don't use multiview, as they have to set this mask to `None`.
|
||||
```diff
|
||||
|
||||
@ -601,13 +601,20 @@ impl super::Adapter {
|
||||
shader_barycentrics_supported,
|
||||
);
|
||||
|
||||
// Re-enable this when multiview is supported on DX12
|
||||
// features.set(wgt::Features::MULTIVIEW, view_instancing);
|
||||
// features.set(wgt::Features::SELECTIVE_MULTIVIEW, view_instancing);
|
||||
features.set(
|
||||
wgt::Features::MULTIVIEW,
|
||||
view_instancing && shader_model >= naga::back::hlsl::ShaderModel::V6_1,
|
||||
);
|
||||
features.set(
|
||||
wgt::Features::SELECTIVE_MULTIVIEW,
|
||||
view_instancing && shader_model >= naga::back::hlsl::ShaderModel::V6_1,
|
||||
);
|
||||
|
||||
features.set(
|
||||
wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW,
|
||||
mesh_shader_supported && view_instancing,
|
||||
mesh_shader_supported
|
||||
&& view_instancing
|
||||
&& shader_model >= naga::back::hlsl::ShaderModel::V6_1,
|
||||
);
|
||||
|
||||
// TODO: Determine if IPresentationManager is supported
|
||||
|
||||
@ -5,6 +5,7 @@ use alloc::{
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use core::{ffi, num::NonZeroU32, ptr, time::Duration};
|
||||
use std::time::Instant;
|
||||
|
||||
@ -983,7 +984,7 @@ impl crate::Device for super::Device {
|
||||
let mut ranges = Vec::with_capacity(total_non_dynamic_entries);
|
||||
|
||||
let mut bind_group_infos =
|
||||
arrayvec::ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default();
|
||||
ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default();
|
||||
for (index, bgl) in desc.bind_group_layouts.iter().enumerate() {
|
||||
let mut info = super::BindGroupInfo {
|
||||
tables: super::TableTypes::empty(),
|
||||
@ -1952,6 +1953,22 @@ impl crate::Device for super::Device {
|
||||
};
|
||||
let flags = Direct3D12::D3D12_PIPELINE_STATE_FLAG_NONE;
|
||||
|
||||
let mut view_instancing =
|
||||
core::pin::pin!(ArrayVec::<Direct3D12::D3D12_VIEW_INSTANCE_LOCATION, 32>::new());
|
||||
if let Some(mask) = desc.multiview_mask {
|
||||
let mask = mask.get();
|
||||
// This array is just what _could_ be rendered to. We actually apply the mask at
|
||||
// renderpass creation time. The `view_index` passed to the shader depends on the
|
||||
// view's index in this array, so if we include every view in this array, `view_index`
|
||||
// actually the texture array layer, like in vulkan.
|
||||
for i in 0..32 - mask.leading_zeros() {
|
||||
view_instancing.push(Direct3D12::D3D12_VIEW_INSTANCE_LOCATION {
|
||||
ViewportArrayIndex: 0,
|
||||
RenderTargetArrayIndex: i,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let mut stream_desc = RenderPipelineStateStreamDesc {
|
||||
// Shared by vertex and mesh pipelines
|
||||
root_signature: desc.layout.shared.signature.as_ref(),
|
||||
@ -1970,6 +1987,16 @@ impl crate::Device for super::Device {
|
||||
node_mask: 0,
|
||||
cached_pso,
|
||||
flags,
|
||||
view_instancing: if !view_instancing.is_empty() {
|
||||
Some(Direct3D12::D3D12_VIEW_INSTANCING_DESC {
|
||||
ViewInstanceCount: view_instancing.len() as u32,
|
||||
pViewInstanceLocations: view_instancing.as_ptr(),
|
||||
// This lets us hide/mask certain values later, at renderpass creation time.
|
||||
Flags: Direct3D12::D3D12_VIEW_INSTANCING_FLAG_ENABLE_VIEW_INSTANCE_MASKING,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
},
|
||||
|
||||
// Optional data that depends on the pipeline type (vertex vs mesh).
|
||||
vertex_shader: Default::default(),
|
||||
|
||||
@ -91,6 +91,7 @@ implement_stream_object! { unsafe D3D12_PIPELINE_STATE_FLAGS => D3D12_PIPELINE_S
|
||||
implement_stream_object! { unsafe D3D12_INPUT_LAYOUT_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT }
|
||||
implement_stream_object! { unsafe D3D12_INDEX_BUFFER_STRIP_CUT_VALUE => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE }
|
||||
implement_stream_object! { unsafe D3D12_STREAM_OUTPUT_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT }
|
||||
implement_stream_object! { unsafe D3D12_VIEW_INSTANCING_DESC => D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING }
|
||||
|
||||
/// Implementaation of a pipeline state stream, which is a sequence of subobjects put into
|
||||
/// a byte array according to some basic alignment rules.
|
||||
@ -183,6 +184,7 @@ pub struct RenderPipelineStateStreamDesc<'a> {
|
||||
pub node_mask: u32,
|
||||
pub cached_pso: D3D12_CACHED_PIPELINE_STATE,
|
||||
pub flags: D3D12_PIPELINE_STATE_FLAGS,
|
||||
pub view_instancing: Option<D3D12_VIEW_INSTANCING_DESC>,
|
||||
|
||||
// Vertex pipeline specific
|
||||
pub vertex_shader: D3D12_SHADER_BYTECODE,
|
||||
@ -230,6 +232,9 @@ impl RenderPipelineStateStreamDesc<'_> {
|
||||
stream.add_object(self.cached_pso);
|
||||
}
|
||||
stream.add_object(self.flags);
|
||||
if let Some(view_instancing) = self.view_instancing {
|
||||
stream.add_object(view_instancing);
|
||||
}
|
||||
if !self.pixel_shader.pShaderBytecode.is_null() {
|
||||
stream.add_object(PixelShader(self.pixel_shader));
|
||||
}
|
||||
|
||||
@ -920,10 +920,9 @@ bitflags_array! {
|
||||
/// Supported platforms:
|
||||
/// - Vulkan
|
||||
/// - Metal
|
||||
/// - DX12
|
||||
/// - OpenGL (web only)
|
||||
///
|
||||
/// DX12 support is a WIP.
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTIVIEW = 1 << 26;
|
||||
/// Enables using 64-bit types for vertex attributes.
|
||||
@ -1249,8 +1248,8 @@ bitflags_array! {
|
||||
///
|
||||
/// Supported platforms
|
||||
/// - Vulkan
|
||||
/// - DX12
|
||||
///
|
||||
/// DX12 will support this when it supports multiview in general.
|
||||
///
|
||||
/// While metal supports this in theory, the behavior of `view_index` differs from vulkan and dx12 so the feature isn't exposed.
|
||||
const SELECTIVE_MULTIVIEW = 1 << 54;
|
||||
|
||||
@ -685,6 +685,9 @@ pub struct RenderPassDescriptor<'a> {
|
||||
/// 2nd layer, you would use 2=0b10. If you aren't using multiview this should be `None`.
|
||||
///
|
||||
/// Note that setting bits higher than the number of texture layers is a validation error.
|
||||
///
|
||||
/// This doesn't influence load/store/clear/etc operations, as those are defined for attachments,
|
||||
/// therefore affecting all attachments. Meaning, this affects only any shaders executed on the `RenderPass`.
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
}
|
||||
#[cfg(send_sync)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user