mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add multiview limits and tests (#8206)
Co-authored-by: Andreas Reich <r_andreas2@web.de> Co-authored-by: Magnus <85136135+SupaMaggie70Incorporated@users.noreply.github.com>
This commit is contained in:
parent
5633ae8649
commit
ad0f3111b7
34
CHANGELOG.md
34
CHANGELOG.md
@ -40,7 +40,7 @@ Bottom level categories:
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Major changes
|
||||
### Major Changes
|
||||
|
||||
#### `wgpu::Instance::enumerate_adapters` is now `async` & available on WebGPU
|
||||
|
||||
@ -73,6 +73,38 @@ SamplerDescriptor {
|
||||
}
|
||||
```
|
||||
|
||||
#### Multiview on all major platforms and support for multiview bitmasks
|
||||
|
||||
Multiview is a feature that allows rendering the same content to multiple layers of a texture. This is useful primarily in VR where you wish to
|
||||
display almost identical content to 2 views, just with a different perspective. Instead of using 2 draw calls or 2 instances for each object, you
|
||||
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.
|
||||
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
|
||||
- wgpu::RenderPassDescriptor {
|
||||
- label: None,
|
||||
- color_attachments: &color_attachments,
|
||||
- depth_stencil_attachment: None,
|
||||
- timestamp_writes: None,
|
||||
- occlusion_query_set: None,
|
||||
- }
|
||||
+ wgpu::RenderPassDescriptor {
|
||||
+ label: None,
|
||||
+ color_attachments: &color_attachments,
|
||||
+ depth_stencil_attachment: None,
|
||||
+ timestamp_writes: None,
|
||||
+ occlusion_query_set: None,
|
||||
+ multiview_mask: NonZero::new(3),
|
||||
+ }
|
||||
```
|
||||
One other breaking change worth noting is that in WGSL `@builtin(view_index)` now requires a type of `u32`, where previously it required `i32`.
|
||||
|
||||
By @SupaMaggie70Incorporated in [#8206](https://github.com/gfx-rs/wgpu/pull/8206).
|
||||
|
||||
### New Features
|
||||
|
||||
- Added support for transient textures on Vulkan and Metal. By @opstic in [#8247](https://github.com/gfx-rs/wgpu/pull/8247)
|
||||
|
||||
@ -224,7 +224,7 @@ impl RenderpassState {
|
||||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -322,7 +322,7 @@ impl RenderpassState {
|
||||
})],
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
},
|
||||
));
|
||||
@ -370,6 +370,7 @@ impl RenderpassState {
|
||||
occlusion_query_set: None,
|
||||
timestamp_writes: None,
|
||||
depth_stencil_attachment: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
let start_idx = pass_number * draws_per_pass;
|
||||
@ -417,6 +418,7 @@ impl RenderpassState {
|
||||
occlusion_query_set: None,
|
||||
timestamp_writes: None,
|
||||
depth_stencil_attachment: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(self.bindless_pipeline.as_ref().unwrap());
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZero;
|
||||
|
||||
use deno_core::cppgc::Ptr;
|
||||
use deno_core::op2;
|
||||
@ -142,6 +143,7 @@ impl GPUCommandEncoder {
|
||||
occlusion_query_set: descriptor
|
||||
.occlusion_query_set
|
||||
.map(|query_set| query_set.id),
|
||||
multiview_mask: NonZero::new(descriptor.multiview_mask),
|
||||
};
|
||||
|
||||
let (render_pass, err) = self
|
||||
|
||||
@ -876,7 +876,7 @@ impl GPUDevice {
|
||||
multisample,
|
||||
fragment,
|
||||
cache: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
};
|
||||
|
||||
let (id, err) = self.instance.device_create_render_pipeline(
|
||||
|
||||
@ -460,6 +460,9 @@ pub(crate) struct GPURenderPassDescriptor {
|
||||
/*#[webidl(default = 50000000)]
|
||||
#[options(enforce_range = true)]
|
||||
pub max_draw_count: u64,*/
|
||||
#[webidl(default = 0)]
|
||||
#[options(enforce_range = true)]
|
||||
pub multiview_mask: u32,
|
||||
}
|
||||
|
||||
#[derive(WebIDL)]
|
||||
|
||||
@ -148,7 +148,7 @@ impl crate::framework::Example for Example {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -276,6 +276,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
};
|
||||
|
||||
// get command encoder
|
||||
|
||||
@ -122,6 +122,7 @@ impl Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.set_bind_group(0, &self.global_group, &[]);
|
||||
@ -229,7 +230,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
||||
@ -106,7 +106,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -129,7 +129,7 @@ impl crate::framework::Example for Example {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -160,7 +160,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
}),
|
||||
)
|
||||
@ -217,7 +217,7 @@ impl crate::framework::Example for Example {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
}),
|
||||
bind_group_layout,
|
||||
@ -273,6 +273,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline_triangle_conservative);
|
||||
@ -295,6 +296,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline_upscale);
|
||||
|
||||
@ -256,7 +256,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -298,7 +298,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
Some(pipeline_wire)
|
||||
@ -356,6 +356,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.push_debug_group("Prepare data for draw.");
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -71,7 +71,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -129,6 +129,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&render_pipeline);
|
||||
rpass.draw(0..3, 0..1);
|
||||
|
||||
@ -133,6 +133,7 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Arc<Window>, wgpu::Color
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ pub mod mesh_shader;
|
||||
pub mod mipmap;
|
||||
pub mod msaa_line;
|
||||
pub mod multiple_render_targets;
|
||||
pub mod multiview;
|
||||
pub mod ray_cube_compute;
|
||||
pub mod ray_cube_fragment;
|
||||
pub mod ray_cube_normals;
|
||||
|
||||
@ -188,6 +188,12 @@ const EXAMPLES: &[ExampleDesc] = &[
|
||||
webgl: false,
|
||||
webgpu: false,
|
||||
},
|
||||
ExampleDesc {
|
||||
name: "multiview",
|
||||
function: wgpu_examples::multiview::main,
|
||||
webgl: false,
|
||||
webgpu: false,
|
||||
},
|
||||
];
|
||||
|
||||
fn get_example_name() -> Option<String> {
|
||||
|
||||
@ -144,6 +144,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.push_debug_group("Prepare data for draw.");
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -104,7 +104,7 @@ impl Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -170,6 +170,7 @@ impl Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
if let Some(ref query_sets) = query_sets {
|
||||
rpass.write_timestamp(&query_sets.timestamp, timestamp_query_index_base);
|
||||
@ -305,7 +306,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -492,6 +493,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.draw_pipeline);
|
||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||
|
||||
@ -77,7 +77,7 @@ impl Example {
|
||||
count: sample_count,
|
||||
..Default::default()
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let mut encoder =
|
||||
@ -307,6 +307,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
})
|
||||
.execute_bundles(iter::once(&self.bundle));
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ impl MultiTargetRenderer {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -182,6 +182,7 @@ impl MultiTargetRenderer {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.set_bind_group(0, &self.bindgroup, &[]);
|
||||
@ -266,7 +267,7 @@ impl TargetRenderer {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -339,6 +340,7 @@ impl TargetRenderer {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.set_bind_group(0, &self.bindgroup_left, &[]);
|
||||
|
||||
182
examples/features/src/multiview/mod.rs
Normal file
182
examples/features/src/multiview/mod.rs
Normal file
@ -0,0 +1,182 @@
|
||||
//! Renders different content to different layers of an array texture using multiview,
|
||||
//! a feature commonly used for VR rendering.
|
||||
|
||||
use std::{num::NonZero, time::Instant};
|
||||
|
||||
use wgpu::util::TextureBlitter;
|
||||
|
||||
const TEXTURE_SIZE: u32 = 512;
|
||||
|
||||
// Change this to demonstrate non-contiguous multiview functionality
|
||||
const LAYER_MASK: u32 = 0b11;
|
||||
|
||||
const NUM_LAYERS: u32 = 32 - LAYER_MASK.leading_zeros();
|
||||
|
||||
pub struct Example {
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
entire_texture_view: wgpu::TextureView,
|
||||
views: Vec<wgpu::TextureView>,
|
||||
start_time: Instant,
|
||||
blitter: TextureBlitter,
|
||||
}
|
||||
|
||||
impl crate::framework::Example for Example {
|
||||
fn init(
|
||||
config: &wgpu::SurfaceConfiguration,
|
||||
_adapter: &wgpu::Adapter,
|
||||
device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) -> Self {
|
||||
let shader_src = include_str!("shader.wgsl");
|
||||
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(shader_src.into()),
|
||||
});
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
vertex: wgpu::VertexState {
|
||||
buffers: &[],
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: Some("fs_main"),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: None,
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview_mask: NonZero::new(LAYER_MASK),
|
||||
multisample: Default::default(),
|
||||
layout: None,
|
||||
depth_stencil: None,
|
||||
cache: None,
|
||||
});
|
||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: TEXTURE_SIZE,
|
||||
height: TEXTURE_SIZE,
|
||||
depth_or_array_layers: NUM_LAYERS,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT
|
||||
| wgpu::TextureUsages::COPY_SRC
|
||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
});
|
||||
let entire_texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
label: None,
|
||||
format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2Array),
|
||||
usage: Some(wgpu::TextureUsages::RENDER_ATTACHMENT),
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: Some(NUM_LAYERS),
|
||||
});
|
||||
let mut views = Vec::new();
|
||||
for i in 0..NUM_LAYERS {
|
||||
views.push(texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
label: None,
|
||||
format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||
usage: Some(wgpu::TextureUsages::TEXTURE_BINDING),
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: i,
|
||||
array_layer_count: Some(1),
|
||||
}));
|
||||
}
|
||||
let blitter = wgpu::util::TextureBlitter::new(device, config.format);
|
||||
Self {
|
||||
pipeline,
|
||||
entire_texture_view,
|
||||
views,
|
||||
blitter,
|
||||
start_time: Instant::now(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &self.entire_texture_view,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.02,
|
||||
g: 0.02,
|
||||
b: 0.02,
|
||||
a: 1.0,
|
||||
}),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: NonZero::new(LAYER_MASK),
|
||||
});
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.draw(0..6, 0..1);
|
||||
}
|
||||
|
||||
let layer = (Instant::now() - self.start_time).as_secs() % NUM_LAYERS as u64;
|
||||
self.blitter
|
||||
.copy(device, &mut encoder, &self.views[layer as usize], view);
|
||||
queue.submit(Some(encoder.finish()));
|
||||
}
|
||||
|
||||
fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn required_features() -> wgpu::Features {
|
||||
wgpu::Features::MULTIVIEW
|
||||
| if !(LAYER_MASK + 1).is_power_of_two() {
|
||||
wgpu::Features::SELECTIVE_MULTIVIEW
|
||||
} else {
|
||||
wgpu::Features::empty()
|
||||
}
|
||||
}
|
||||
|
||||
fn required_limits() -> wgpu::Limits {
|
||||
wgpu::Limits {
|
||||
max_multiview_view_count: NUM_LAYERS,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn resize(
|
||||
&mut self,
|
||||
_config: &wgpu::SurfaceConfiguration,
|
||||
_device: &wgpu::Device,
|
||||
_queue: &wgpu::Queue,
|
||||
) {
|
||||
// empty
|
||||
}
|
||||
fn update(&mut self, _event: winit::event::WindowEvent) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
crate::framework::run::<Example>("multiview");
|
||||
}
|
||||
11
examples/features/src/multiview/shader.wgsl
Normal file
11
examples/features/src/multiview/shader.wgsl
Normal file
@ -0,0 +1,11 @@
|
||||
const triangles = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
|
||||
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
|
||||
return vec4f(triangles[vertex_index], 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(@builtin(view_index) view_index: u32) -> @location(0) vec4f {
|
||||
return vec4f(f32(view_index) * 0.25 + 0.125, 1.0 - f32(view_index) * 0.25, 1.0 - 0.5 * f32(view_index), 1.0);
|
||||
}
|
||||
@ -326,7 +326,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -469,6 +469,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.blit_pipeline);
|
||||
|
||||
@ -216,7 +216,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -355,6 +355,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -317,7 +317,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -455,6 +455,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.blit_pipeline);
|
||||
|
||||
@ -395,7 +395,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -535,6 +535,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -239,7 +239,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -348,6 +348,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -309,7 +309,7 @@ impl crate::framework::Example for Example {
|
||||
write_mask: Default::default(),
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -414,6 +414,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.blit_pipeline);
|
||||
|
||||
@ -68,7 +68,7 @@ async fn run(_path: Option<String>) {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -95,6 +95,7 @@ async fn run(_path: Option<String>) {
|
||||
depth_stencil_attachment: None,
|
||||
occlusion_query_set: None,
|
||||
timestamp_writes: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
|
||||
@ -518,7 +518,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -653,7 +653,7 @@ impl crate::framework::Example for Example {
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -771,6 +771,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_pipeline(&self.shadow_pass.pipeline);
|
||||
pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]);
|
||||
@ -816,6 +817,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_pipeline(&self.forward_pass.pipeline);
|
||||
pass.set_bind_group(0, &self.forward_pass.bind_group, &[]);
|
||||
|
||||
@ -218,7 +218,7 @@ impl crate::framework::Example for Example {
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let entity_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
@ -252,7 +252,7 @@ impl crate::framework::Example for Example {
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -444,6 +444,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||
|
||||
@ -146,7 +146,7 @@ impl<const SRGB: bool> crate::framework::Example for Example<SRGB> {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -196,6 +196,7 @@ impl<const SRGB: bool> crate::framework::Example for Example<SRGB> {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.push_debug_group("Prepare data for draw.");
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -100,7 +100,7 @@ impl crate::framework::Example for Example {
|
||||
bias: Default::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -136,7 +136,7 @@ impl crate::framework::Example for Example {
|
||||
bias: Default::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -222,6 +222,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_stencil_reference(1);
|
||||
|
||||
@ -358,7 +358,7 @@ impl crate::framework::Example for Example {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None
|
||||
});
|
||||
|
||||
@ -402,6 +402,7 @@ impl crate::framework::Example for Example {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
|
||||
@ -358,7 +358,7 @@ fn render_pass(
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let render_target = device.create_texture(&wgpu::TextureDescriptor {
|
||||
@ -395,6 +395,7 @@ fn render_pass(
|
||||
end_of_pass_write_index: Some(*next_unused_query + 1),
|
||||
}),
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
*next_unused_query += 2;
|
||||
|
||||
|
||||
@ -186,7 +186,7 @@ impl WgpuContext {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let surface_config = surface
|
||||
@ -319,6 +319,7 @@ async fn run(event_loop: EventLoop<()>, window: Arc<Window>) {
|
||||
depth_stencil_attachment: None,
|
||||
occlusion_query_set: None,
|
||||
timestamp_writes: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&wgpu_context_ref.pipeline);
|
||||
// (9)
|
||||
|
||||
@ -567,7 +567,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
// No multisampling is used.
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
// No pipeline caching is used
|
||||
cache: None,
|
||||
});
|
||||
@ -605,7 +605,7 @@ impl crate::framework::Example for Example {
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None
|
||||
});
|
||||
|
||||
@ -750,6 +750,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.execute_bundles([&self.terrain_bundle]);
|
||||
@ -778,6 +779,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&self.terrain_pipeline);
|
||||
rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]);
|
||||
@ -805,6 +807,7 @@ impl crate::framework::Example for Example {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.water_pipeline);
|
||||
|
||||
@ -107,6 +107,7 @@ impl State {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
// If you wanted to call any drawing commands, they would go here.
|
||||
|
||||
@ -5215,8 +5215,13 @@ const fn glsl_built_in(built_in: crate::BuiltIn, options: VaryingOptions) -> &'s
|
||||
"gl_FragCoord"
|
||||
}
|
||||
}
|
||||
Bi::ViewIndex if options.targeting_webgl => "int(gl_ViewID_OVR)",
|
||||
Bi::ViewIndex => "gl_ViewIndex",
|
||||
Bi::ViewIndex => {
|
||||
if options.targeting_webgl {
|
||||
"gl_ViewID_OVR"
|
||||
} else {
|
||||
"uint(gl_ViewIndex)"
|
||||
}
|
||||
}
|
||||
// vertex
|
||||
Bi::BaseInstance => "uint(gl_BaseInstance)",
|
||||
Bi::BaseVertex => "uint(gl_BaseVertex)",
|
||||
|
||||
@ -173,6 +173,7 @@ impl crate::BuiltIn {
|
||||
// to this field will get replaced with references to `SPECIAL_CBUF_VAR`
|
||||
// in `Writer::write_expr`.
|
||||
Self::NumWorkGroups => "SV_GroupID",
|
||||
Self::ViewIndex => "SV_ViewID",
|
||||
// These builtins map to functions
|
||||
Self::SubgroupSize
|
||||
| Self::SubgroupInvocationId
|
||||
@ -181,7 +182,7 @@ impl crate::BuiltIn {
|
||||
Self::BaseInstance | Self::BaseVertex | Self::WorkGroupSize => {
|
||||
return Err(Error::Unimplemented(format!("builtin {self:?}")))
|
||||
}
|
||||
Self::PointSize | Self::ViewIndex | Self::PointCoord | Self::DrawID => {
|
||||
Self::PointSize | Self::PointCoord | Self::DrawID => {
|
||||
return Err(Error::Custom(format!("Unsupported builtin {self:?}")))
|
||||
}
|
||||
Self::CullPrimitive => "SV_CullPrimitive",
|
||||
|
||||
@ -650,6 +650,8 @@ pub enum Error {
|
||||
ResolveArraySizeError(#[from] proc::ResolveArraySizeError),
|
||||
#[error("entry point with stage {0:?} and name '{1}' not found")]
|
||||
EntryPointNotFound(ir::ShaderStage, String),
|
||||
#[error("requires shader model {1:?} for reason: {0}")]
|
||||
ShaderModelTooLow(String, ShaderModel),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
|
||||
@ -569,6 +569,14 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
) -> BackendResult {
|
||||
match *binding {
|
||||
Some(crate::Binding::BuiltIn(builtin)) if !is_subgroup_builtin_binding(binding) => {
|
||||
if builtin == crate::BuiltIn::ViewIndex
|
||||
&& self.options.shader_model < ShaderModel::V6_1
|
||||
{
|
||||
return Err(Error::ShaderModelTooLow(
|
||||
"used @builtin(view_index) or SV_ViewID".to_string(),
|
||||
ShaderModel::V6_1,
|
||||
));
|
||||
}
|
||||
let builtin_str = builtin.to_hlsl_str()?;
|
||||
write!(self.out, " : {builtin_str}")?;
|
||||
}
|
||||
|
||||
@ -530,6 +530,12 @@ impl Options {
|
||||
crate::BuiltIn::PrimitiveIndex if self.lang_version < (2, 3) => {
|
||||
return Err(Error::UnsupportedAttribute("primitive_id".to_string()));
|
||||
}
|
||||
// macOS: since Metal 2.3
|
||||
// iOS: Since Metal 2.2
|
||||
// https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf#page=114
|
||||
crate::BuiltIn::ViewIndex if self.lang_version < (2, 2) => {
|
||||
return Err(Error::UnsupportedAttribute("amplification_id".to_string()));
|
||||
}
|
||||
// macOS: Since Metal 2.2
|
||||
// iOS: Since Metal 2.3 (check depends on https://github.com/gfx-rs/wgpu/issues/4414)
|
||||
crate::BuiltIn::Barycentric if self.lang_version < (2, 3) => {
|
||||
@ -674,6 +680,7 @@ impl ResolvedBinding {
|
||||
let name = match built_in {
|
||||
Bi::Position { invariant: false } => "position",
|
||||
Bi::Position { invariant: true } => "position, invariant",
|
||||
Bi::ViewIndex => "amplification_id",
|
||||
// vertex
|
||||
Bi::BaseInstance => "base_instance",
|
||||
Bi::BaseVertex => "base_vertex",
|
||||
@ -701,7 +708,7 @@ impl ResolvedBinding {
|
||||
Bi::SubgroupId => "simdgroup_index_in_threadgroup",
|
||||
Bi::SubgroupSize => "threads_per_simdgroup",
|
||||
Bi::SubgroupInvocationId => "thread_index_in_simdgroup",
|
||||
Bi::CullDistance | Bi::ViewIndex | Bi::DrawID => {
|
||||
Bi::CullDistance | Bi::DrawID => {
|
||||
return Err(Error::UnsupportedBuiltIn(built_in))
|
||||
}
|
||||
Bi::CullPrimitive => "primitive_culled",
|
||||
|
||||
@ -301,7 +301,7 @@ impl VaryingContext<'_> {
|
||||
St::Vertex | St::Fragment | St::Task | St::Mesh => !self.output,
|
||||
St::Compute => false,
|
||||
},
|
||||
*ty_inner == Ti::Scalar(crate::Scalar::I32),
|
||||
*ty_inner == Ti::Scalar(crate::Scalar::U32),
|
||||
),
|
||||
Bi::FragDepth => (
|
||||
self.stage == St::Fragment && self.output,
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
glsl_multiview = 2
|
||||
god_mode = true
|
||||
targets = "SPIRV | GLSL | WGSL"
|
||||
|
||||
[msl]
|
||||
lang_version = [2, 3]
|
||||
|
||||
[hlsl]
|
||||
shader_model = "V6_1"
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
@fragment
|
||||
fn main(@builtin(view_index) view_index: i32) {}
|
||||
fn main(@builtin(view_index) view_index: u32) {}
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
@fragment
|
||||
fn main(@builtin(view_index) view_index: i32) {}
|
||||
fn main(@builtin(view_index) view_index: u32) {}
|
||||
|
||||
@ -6,7 +6,7 @@ precision highp int;
|
||||
|
||||
|
||||
void main() {
|
||||
int view_index = gl_ViewIndex;
|
||||
uint view_index = uint(gl_ViewIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ precision highp int;
|
||||
|
||||
|
||||
void main() {
|
||||
int view_index = int(gl_ViewID_OVR);
|
||||
uint view_index = gl_ViewID_OVR;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
9
naga/tests/out/hlsl/wgsl-multiview.hlsl
Normal file
9
naga/tests/out/hlsl/wgsl-multiview.hlsl
Normal file
@ -0,0 +1,9 @@
|
||||
struct FragmentInput_main {
|
||||
uint view_index_1 : SV_ViewID;
|
||||
};
|
||||
|
||||
void main(FragmentInput_main fragmentinput_main)
|
||||
{
|
||||
uint view_index = fragmentinput_main.view_index_1;
|
||||
return;
|
||||
}
|
||||
12
naga/tests/out/hlsl/wgsl-multiview.ron
Normal file
12
naga/tests/out/hlsl/wgsl-multiview.ron
Normal file
@ -0,0 +1,12 @@
|
||||
(
|
||||
vertex:[
|
||||
],
|
||||
fragment:[
|
||||
(
|
||||
entry_point:"main",
|
||||
target_profile:"ps_6_1",
|
||||
),
|
||||
],
|
||||
compute:[
|
||||
],
|
||||
)
|
||||
14
naga/tests/out/msl/wgsl-multiview.msl
Normal file
14
naga/tests/out/msl/wgsl-multiview.msl
Normal file
@ -0,0 +1,14 @@
|
||||
// language: metal2.3
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using metal::uint;
|
||||
|
||||
|
||||
struct main_Input {
|
||||
};
|
||||
fragment void main_(
|
||||
uint view_index [[amplification_id]]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -12,7 +12,7 @@ OpExecutionMode %8 OriginUpperLeft
|
||||
OpDecorate %5 BuiltIn ViewIndex
|
||||
OpDecorate %5 Flat
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeInt 32 1
|
||||
%3 = OpTypeInt 32 0
|
||||
%6 = OpTypePointer Input %3
|
||||
%5 = OpVariable %6 Input
|
||||
%9 = OpTypeFunction %2
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@fragment
|
||||
fn main(@builtin(view_index) view_index: i32) {
|
||||
fn main(@builtin(view_index) view_index: u32) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -674,7 +674,7 @@ impl Player {
|
||||
depth_stencil: desc.depth_stencil,
|
||||
multisample: desc.multisample,
|
||||
fragment,
|
||||
multiview: desc.multiview,
|
||||
multiview_mask: desc.multiview_mask,
|
||||
cache: desc.cache.map(|id| self.resolve_pipeline_cache_id(id)),
|
||||
}
|
||||
}
|
||||
@ -851,6 +851,7 @@ impl Player {
|
||||
depth_stencil_attachment,
|
||||
timestamp_writes,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
} => Command::RunRenderPass {
|
||||
pass: self.resolve_render_pass(pass),
|
||||
color_attachments: self.resolve_color_attachments(color_attachments),
|
||||
@ -858,6 +859,7 @@ impl Player {
|
||||
.map(|att| self.resolve_depth_stencil_attachment(att)),
|
||||
timestamp_writes: timestamp_writes.map(|tw| self.resolve_pass_timestamp_writes(tw)),
|
||||
occlusion_query_set: occlusion_query_set.map(|qs| self.resolve_query_set_id(qs)),
|
||||
multiview_mask,
|
||||
},
|
||||
Command::BuildAccelerationStructures { blas, tlas } => {
|
||||
Command::BuildAccelerationStructures {
|
||||
|
||||
@ -207,7 +207,7 @@ async fn binding_array_sampled_textures(ctx: TestingContext, partially_bound: bo
|
||||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
cache: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
let mut encoder = ctx
|
||||
@ -228,6 +228,7 @@ async fn binding_array_sampled_textures(ctx: TestingContext, partially_bound: bo
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.set_bind_group(0, &bind_group, &[]);
|
||||
|
||||
@ -43,7 +43,7 @@ async fn clip_distances(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -87,6 +87,7 @@ async fn clip_distances(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.draw(0..3, 0..1);
|
||||
|
||||
@ -346,6 +346,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
drop(pass);
|
||||
ctx.queue.submit([encoder_for_render_pass.finish()]);
|
||||
@ -458,7 +459,7 @@ static DEVICE_DESTROY_THEN_MORE: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
fragment: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -616,7 +617,7 @@ static DIFFERENT_BGL_ORDER_BW_SHADER_AND_API: GpuTestConfiguration = GpuTestConf
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
||||
@ -207,7 +207,7 @@ async fn run_test(ctx: TestingContext, test_data: TestData, expect_noop: bool) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -272,6 +272,7 @@ async fn run_test(ctx: TestingContext, test_data: TestData, expect_noop: bool) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
@ -697,7 +698,7 @@ async fn indirect_buffer_offsets(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -747,6 +748,7 @@ async fn indirect_buffer_offsets(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -96,7 +96,7 @@ async fn dual_source_blending_disabled(ctx: TestingContext) {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
},
|
||||
@ -159,7 +159,7 @@ async fn dual_source_blending_enabled(ctx: TestingContext) {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
|
||||
|
||||
@ -77,6 +77,7 @@ static DROP_ENCODER_AFTER_ERROR: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
// This viewport is invalid because it has negative size.
|
||||
|
||||
@ -36,6 +36,7 @@ mod instance;
|
||||
mod life_cycle;
|
||||
mod mem_leaks;
|
||||
mod mesh_shader;
|
||||
mod multiview;
|
||||
mod occlusion_query;
|
||||
mod oob_indexing;
|
||||
mod oom;
|
||||
@ -99,6 +100,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
|
||||
life_cycle::all_tests(&mut tests);
|
||||
mem_leaks::all_tests(&mut tests);
|
||||
mesh_shader::all_tests(&mut tests);
|
||||
multiview::all_tests(&mut tests);
|
||||
occlusion_query::all_tests(&mut tests);
|
||||
oob_indexing::all_tests(&mut tests);
|
||||
oom::all_tests(&mut tests);
|
||||
|
||||
@ -126,7 +126,7 @@ async fn draw_test_with_reports(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -207,6 +207,7 @@ async fn draw_test_with_reports(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -242,6 +242,7 @@ fn mesh_pipeline_build(ctx: &TestingContext, info: MeshPipelineTestInfo) {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
pass.draw_mesh_tasks(1, 1, 1);
|
||||
@ -348,6 +349,7 @@ fn mesh_draw(ctx: &TestingContext, draw_type: DrawType) {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
pass.set_pipeline(&pipeline);
|
||||
match draw_type {
|
||||
|
||||
193
tests/tests/wgpu-gpu/multiview/mod.rs
Normal file
193
tests/tests/wgpu-gpu/multiview/mod.rs
Normal file
@ -0,0 +1,193 @@
|
||||
use std::num::NonZero;
|
||||
|
||||
use wgpu::{Features, Limits};
|
||||
use wgpu_test::{
|
||||
gpu_test, GpuTestConfiguration, GpuTestInitializer, TestParameters, TestingContext,
|
||||
};
|
||||
|
||||
pub fn all_tests(vec: &mut Vec<GpuTestInitializer>) {
|
||||
vec.push(DRAW_MULTIVIEW_SINGLE);
|
||||
vec.push(DRAW_MULTIVIEW);
|
||||
vec.push(DRAW_MULTIVIEW_NONCONTIGUOUS);
|
||||
}
|
||||
|
||||
#[gpu_test]
|
||||
static DRAW_MULTIVIEW_SINGLE: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.features(Features::MULTIVIEW)
|
||||
.limits(Limits {
|
||||
max_multiview_view_count: 1,
|
||||
..Limits::defaults()
|
||||
}),
|
||||
)
|
||||
.run_async(|ctx| run_test(ctx, 0b1));
|
||||
|
||||
#[gpu_test]
|
||||
static DRAW_MULTIVIEW: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.features(Features::MULTIVIEW)
|
||||
.limits(Limits {
|
||||
max_multiview_view_count: 2,
|
||||
..Limits::defaults()
|
||||
}),
|
||||
)
|
||||
.run_async(|ctx| run_test(ctx, 0b11));
|
||||
|
||||
#[gpu_test]
|
||||
static DRAW_MULTIVIEW_NONCONTIGUOUS: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
.parameters(
|
||||
TestParameters::default()
|
||||
.features(Features::MULTIVIEW | Features::SELECTIVE_MULTIVIEW)
|
||||
.limits(Limits {
|
||||
max_multiview_view_count: 4,
|
||||
..Limits::defaults()
|
||||
}),
|
||||
)
|
||||
.run_async(|ctx| run_test(ctx, 0b1001));
|
||||
|
||||
async fn run_test(ctx: TestingContext, layer_mask: u32) {
|
||||
let num_layers = 32 - layer_mask.leading_zeros();
|
||||
|
||||
let shader_src = include_str!("shader.wgsl");
|
||||
|
||||
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,
|
||||
vertex: wgpu::VertexState {
|
||||
buffers: &[],
|
||||
module: &shader,
|
||||
entry_point: Some("vs_main"),
|
||||
compilation_options: Default::default(),
|
||||
},
|
||||
primitive: wgpu::PrimitiveState::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_mask: NonZero::new(layer_mask),
|
||||
multisample: Default::default(),
|
||||
layout: None,
|
||||
depth_stencil: None,
|
||||
cache: None,
|
||||
};
|
||||
|
||||
const TEXTURE_SIZE: u32 = 256;
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
let texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: TEXTURE_SIZE,
|
||||
height: TEXTURE_SIZE,
|
||||
depth_or_array_layers: 32 - layer_mask.leading_zeros(),
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::R8Unorm,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||
view_formats: &[],
|
||||
});
|
||||
let entire_texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
label: None,
|
||||
format: Some(wgpu::TextureFormat::R8Unorm),
|
||||
dimension: Some(wgpu::TextureViewDimension::D2Array),
|
||||
usage: Some(wgpu::TextureUsages::RENDER_ATTACHMENT),
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
base_mip_level: 0,
|
||||
mip_level_count: None,
|
||||
base_array_layer: 0,
|
||||
array_layer_count: Some(num_layers),
|
||||
});
|
||||
let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: None,
|
||||
size: TEXTURE_SIZE as u64 * TEXTURE_SIZE as u64 * num_layers as u64,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let clear_color = 0.0;
|
||||
|
||||
let mut encoder = ctx
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||
{
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &entire_texture_view,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: NonZero::new(layer_mask),
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.draw(0..6, 0..1);
|
||||
}
|
||||
encoder.copy_texture_to_buffer(
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture: &texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d { x: 0, y: 0, z: 0 },
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
wgpu::TexelCopyBufferInfo {
|
||||
buffer: &readback_buffer,
|
||||
layout: wgpu::TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(TEXTURE_SIZE),
|
||||
rows_per_image: Some(TEXTURE_SIZE),
|
||||
},
|
||||
},
|
||||
wgpu::Extent3d {
|
||||
width: TEXTURE_SIZE,
|
||||
height: TEXTURE_SIZE,
|
||||
depth_or_array_layers: num_layers,
|
||||
},
|
||||
);
|
||||
ctx.queue.submit([encoder.finish()]);
|
||||
|
||||
let slice = readback_buffer.slice(..);
|
||||
slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||
|
||||
ctx.async_poll(wgpu::PollType::wait_indefinitely())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let data = slice.get_mapped_range();
|
||||
let each_texture_size = (TEXTURE_SIZE * TEXTURE_SIZE) as usize;
|
||||
assert_eq!(data.len(), each_texture_size * num_layers as usize);
|
||||
for view_idx in 0..num_layers as usize {
|
||||
let target_value = if (layer_mask & (1 << view_idx)) != 0 {
|
||||
(32 + 64 * view_idx) as u8
|
||||
} else {
|
||||
(clear_color * 255.0) as u8
|
||||
};
|
||||
// Some metal devices automatically initialize stuff to 255, so I decided to use 128 instead of that
|
||||
let failed_value = data[each_texture_size * view_idx..each_texture_size * (view_idx + 1)]
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|b| b.abs_diff(target_value) > 1);
|
||||
assert_eq!(failed_value, None, "Expected {target_value}");
|
||||
}
|
||||
}
|
||||
11
tests/tests/wgpu-gpu/multiview/shader.wgsl
Normal file
11
tests/tests/wgpu-gpu/multiview/shader.wgsl
Normal file
@ -0,0 +1,11 @@
|
||||
const triangles = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
|
||||
|
||||
@vertex
|
||||
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
|
||||
return vec4f(triangles[vertex_index], 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(@builtin(view_index) view_index: u32) -> @location(0) vec4f {
|
||||
return vec4f(f32(view_index) * 0.25 + 0.125);
|
||||
}
|
||||
@ -56,7 +56,7 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -84,6 +84,7 @@ static OCCLUSION_QUERY: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: Some(&query_set),
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ static RENDER_PIPELINE_DEFAULT_LAYOUT_BAD_MODULE: GpuTestConfiguration =
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
fragment: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -182,7 +182,7 @@ static RENDER_PIPELINE_DEFAULT_LAYOUT_BAD_BGL_INDEX: GpuTestConfiguration =
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -223,7 +223,7 @@ static NO_TARGETLESS_RENDER: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||
..Default::default()
|
||||
},
|
||||
fragment: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ fn test_planar_texture_creation_sampling(
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -101,6 +101,7 @@ fn test_planar_texture_creation_sampling(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_bind_group(0, &bind_group, &[]);
|
||||
@ -142,7 +143,7 @@ fn test_planar_texture_rendering(
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -170,7 +171,7 @@ fn test_planar_texture_rendering(
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -190,6 +191,7 @@ fn test_planar_texture_rendering(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&y_pipeline);
|
||||
rpass.draw(0..3, 0..1);
|
||||
@ -206,6 +208,7 @@ fn test_planar_texture_rendering(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&uv_pipeline);
|
||||
rpass.draw(0..3, 0..1);
|
||||
|
||||
@ -301,7 +301,7 @@ async fn render_pass_test(ctx: &TestingContext, use_render_bundle: bool) {
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ async fn multi_stage_data_binding_test(ctx: TestingContext) {
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -166,6 +166,7 @@ async fn multi_stage_data_binding_test(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -84,7 +84,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
write_mask: ColorWrites::all(),
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -116,7 +116,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
write_mask: ColorWrites::all(),
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -156,6 +156,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
double_rpass.set_pipeline(&double_pipeline);
|
||||
@ -192,6 +193,7 @@ static PASS_RESET_VERTEX_BUFFER: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
single_rpass.set_pipeline(&single_pipeline);
|
||||
|
||||
@ -68,7 +68,7 @@ async fn test_impl(ctx: &TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -98,6 +98,7 @@ async fn test_impl(ctx: &TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
|
||||
@ -68,7 +68,7 @@ async fn test_impl(ctx: &TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -98,6 +98,7 @@ async fn test_impl(ctx: &TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
|
||||
@ -53,7 +53,7 @@ static ALLOW_INPUT_NOT_CONSUMED: GpuTestConfiguration = GpuTestConfiguration::ne
|
||||
write_mask: ColorWrites::all(),
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
});
|
||||
|
||||
@ -91,6 +91,7 @@ async fn render_pass_resource_ownership(ctx: TestingContext) {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: Some(&occlusion_query_set),
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
// Drop render pass attachments right away.
|
||||
@ -548,7 +549,7 @@ fn resource_setup(ctx: &TestingContext) -> ResourceSetup {
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
|
||||
@ -106,7 +106,7 @@ async fn run_test(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -203,6 +203,7 @@ async fn run_test(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||
@ -318,7 +319,7 @@ async fn run_test_3d(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -386,6 +387,7 @@ async fn run_test_3d(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||
|
||||
@ -69,7 +69,7 @@ async fn scissor_test_impl(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -98,6 +98,7 @@ async fn scissor_test_impl(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
render_pass.set_pipeline(&pipeline);
|
||||
render_pass.set_scissor_rect(
|
||||
|
||||
@ -95,7 +95,7 @@ async fn barycentric(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -138,6 +138,7 @@ async fn barycentric(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -150,7 +150,7 @@ async fn pulling_common(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -193,6 +193,7 @@ async fn pulling_common(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -113,7 +113,7 @@ async fn reinterpret(
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
@ -151,6 +151,7 @@ async fn reinterpret(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
rpass.set_pipeline(&pipeline);
|
||||
rpass.set_bind_group(0, &bind_group, &[]);
|
||||
|
||||
@ -64,7 +64,7 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -119,6 +119,7 @@ static RESOLVE_WITH_TRANSIENT: GpuTestConfiguration = GpuTestConfiguration::new(
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&pipeline);
|
||||
|
||||
@ -314,7 +314,7 @@ async fn vertex_formats_common(ctx: TestingContext, tests: &[Test<'_>]) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
|
||||
@ -360,6 +360,7 @@ async fn vertex_formats_common(ctx: TestingContext, tests: &[Test<'_>]) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
rpass.set_vertex_buffer(0, buffer_input.slice(..));
|
||||
|
||||
@ -259,7 +259,7 @@ async fn vertex_index_common(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let builtin_pipeline = ctx.device.create_render_pipeline(&pipeline_desc);
|
||||
@ -366,6 +366,7 @@ async fn vertex_index_common(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
{
|
||||
|
||||
@ -99,7 +99,7 @@ async fn set_array_stride_to_0(ctx: TestingContext) {
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let mut first_pipeline_desc = pipeline_desc.clone();
|
||||
@ -148,6 +148,7 @@ async fn set_array_stride_to_0(ctx: TestingContext) {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
// The D3D12 backend used to not set the stride of vertex buffers if it was 0.
|
||||
|
||||
@ -173,6 +173,7 @@ impl<'ctx> TestCase<'ctx> {
|
||||
}),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
ctx.queue.submit([encoder.finish()]);
|
||||
} else {
|
||||
@ -259,6 +260,7 @@ impl<'ctx> TestCase<'ctx> {
|
||||
),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -284,6 +286,7 @@ impl<'ctx> TestCase<'ctx> {
|
||||
),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -309,6 +312,7 @@ impl<'ctx> TestCase<'ctx> {
|
||||
),
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -652,7 +652,7 @@ var tex: texture_external;
|
||||
write_mask: ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
@ -685,6 +685,7 @@ var tex: texture_external;
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
pass.set_pipeline(&pipeline);
|
||||
|
||||
@ -58,7 +58,7 @@ fn frag() -> @location({}) vec4f {{
|
||||
primitive: Default::default(),
|
||||
depth_stencil: None,
|
||||
multisample: Default::default(),
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
})
|
||||
},
|
||||
|
||||
@ -674,6 +674,7 @@ fn transient_invalid_storeop() {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
});
|
||||
|
||||
drop(invalid_render_pass);
|
||||
|
||||
@ -218,7 +218,7 @@ impl RenderBundleEncoder {
|
||||
}
|
||||
sc
|
||||
},
|
||||
multiview: desc.multiview,
|
||||
multiview_mask: desc.multiview,
|
||||
},
|
||||
|
||||
is_depth_read_only,
|
||||
@ -239,7 +239,7 @@ impl RenderBundleEncoder {
|
||||
depth_stencil: None,
|
||||
},
|
||||
sample_count: 0,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
},
|
||||
is_depth_read_only: false,
|
||||
is_stencil_read_only: false,
|
||||
|
||||
@ -532,7 +532,7 @@ fn clear_texture_via_render_passes(
|
||||
sample_count: dst_texture.desc.sample_count,
|
||||
color_attachments,
|
||||
depth_stencil_attachment,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
})
|
||||
|
||||
@ -71,6 +71,13 @@ pub enum DrawError {
|
||||
limit: u32,
|
||||
max_total: u32,
|
||||
},
|
||||
#[error(
|
||||
"Mesh shader calls in multiview render passes require enabling the `EXPERIMENTAL_MESH_SHADER_MULTIVIEW` feature, and the highest bit ({highest_view_index}) in the multiview mask must be <= `Limits::max_multiview_view_count` ({max_multiviews})"
|
||||
)]
|
||||
MeshPipelineMultiviewLimitsViolated {
|
||||
highest_view_index: u32,
|
||||
max_multiviews: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl WebGpuError for DrawError {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use core::convert::Infallible;
|
||||
use core::{convert::Infallible, num::NonZero};
|
||||
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
#[cfg(feature = "serde")]
|
||||
@ -171,6 +171,7 @@ pub enum Command<R: ReferenceType> {
|
||||
Option<crate::command::ResolvedRenderPassDepthStencilAttachment<R::TextureView>>,
|
||||
timestamp_writes: Option<crate::command::PassTimestampWrites<R::QuerySet>>,
|
||||
occlusion_query_set: Option<R::QuerySet>,
|
||||
multiview_mask: Option<NonZero<u32>>,
|
||||
},
|
||||
BuildAccelerationStructures {
|
||||
blas: Vec<crate::ray_tracing::OwnedBlasBuildEntry<R>>,
|
||||
|
||||
@ -1019,6 +1019,7 @@ impl CommandEncoder {
|
||||
depth_stencil_attachment,
|
||||
timestamp_writes,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
} => {
|
||||
api_log!(
|
||||
"Begin encoding render pass with '{}' label",
|
||||
@ -1031,6 +1032,7 @@ impl CommandEncoder {
|
||||
depth_stencil_attachment,
|
||||
timestamp_writes,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
);
|
||||
match res.as_ref() {
|
||||
Err(err) => api_log!("Finished encoding render pass ({err:?})"),
|
||||
|
||||
@ -250,6 +250,8 @@ pub struct RenderPassDescriptor<'a> {
|
||||
pub timestamp_writes: Option<&'a PassTimestampWrites>,
|
||||
/// Defines where the occlusion query results will be stored for this pass.
|
||||
pub occlusion_query_set: Option<id::QuerySetId>,
|
||||
/// The multiview array layers that will be used
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
/// Describes the attachments of a render pass.
|
||||
@ -265,6 +267,8 @@ struct ArcRenderPassDescriptor<'a> {
|
||||
pub timestamp_writes: Option<ArcPassTimestampWrites>,
|
||||
/// Defines where the occlusion query results will be stored for this pass.
|
||||
pub occlusion_query_set: Option<Arc<QuerySet>>,
|
||||
/// The multiview array layers that will be used
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
pub type RenderBasePass = BasePass<ArcRenderCommand, RenderPassError>;
|
||||
@ -292,6 +296,7 @@ pub struct RenderPass {
|
||||
depth_stencil_attachment: Option<ResolvedRenderPassDepthStencilAttachment<Arc<TextureView>>>,
|
||||
timestamp_writes: Option<ArcPassTimestampWrites>,
|
||||
occlusion_query_set: Option<Arc<QuerySet>>,
|
||||
multiview_mask: Option<NonZeroU32>,
|
||||
|
||||
// Resource binding dedupe state.
|
||||
current_bind_groups: BindGroupStateChange,
|
||||
@ -307,6 +312,7 @@ impl RenderPass {
|
||||
color_attachments,
|
||||
depth_stencil_attachment,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
} = desc;
|
||||
|
||||
Self {
|
||||
@ -316,6 +322,7 @@ impl RenderPass {
|
||||
depth_stencil_attachment,
|
||||
timestamp_writes,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
|
||||
current_bind_groups: BindGroupStateChange::new(),
|
||||
current_pipeline: StateChange::new(),
|
||||
@ -330,6 +337,7 @@ impl RenderPass {
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
current_bind_groups: BindGroupStateChange::new(),
|
||||
current_pipeline: StateChange::new(),
|
||||
}
|
||||
@ -353,6 +361,7 @@ impl fmt::Debug for RenderPass {
|
||||
"push constant u32 count",
|
||||
&self.base.push_constant_data.len(),
|
||||
)
|
||||
.field("multiview mask", &self.multiview_mask)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@ -806,6 +815,8 @@ pub enum RenderPassErrorInner {
|
||||
"Multiview pass texture views with more than one array layer must have D2Array dimension"
|
||||
)]
|
||||
MultiViewDimensionMismatch,
|
||||
#[error("Multiview view count limit violated")]
|
||||
TooManyMultiviewViews,
|
||||
#[error("missing occlusion query set")]
|
||||
MissingOcclusionQuerySet,
|
||||
#[error(transparent)]
|
||||
@ -907,6 +918,7 @@ impl WebGpuError for RenderPassError {
|
||||
| RenderPassErrorInner::PushConstantOutOfMemory
|
||||
| RenderPassErrorInner::MultiViewMismatch
|
||||
| RenderPassErrorInner::MultiViewDimensionMismatch
|
||||
| RenderPassErrorInner::TooManyMultiviewViews
|
||||
| RenderPassErrorInner::MissingOcclusionQuerySet
|
||||
| RenderPassErrorInner::PassEnded => return ErrorType::Validation,
|
||||
};
|
||||
@ -942,7 +954,7 @@ struct RenderPassInfo {
|
||||
extent: wgt::Extent3d,
|
||||
|
||||
divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, Arc<TextureView>)>,
|
||||
multiview: Option<NonZeroU32>,
|
||||
multiview_mask: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
impl RenderPassInfo {
|
||||
@ -996,6 +1008,7 @@ impl RenderPassInfo {
|
||||
pending_query_resets: &mut QueryResetMap,
|
||||
pending_discard_init_fixups: &mut SurfacesInDiscardState,
|
||||
snatch_guard: &SnatchGuard<'_>,
|
||||
multiview_mask: Option<NonZeroU32>,
|
||||
) -> Result<Self, RenderPassErrorInner> {
|
||||
profiling::scope!("RenderPassInfo::start");
|
||||
|
||||
@ -1040,8 +1053,11 @@ impl RenderPassInfo {
|
||||
}
|
||||
} else {
|
||||
// Multiview is only supported if the feature is enabled
|
||||
if this_multiview.is_some() {
|
||||
if let Some(this_multiview) = this_multiview {
|
||||
device.require_features(wgt::Features::MULTIVIEW)?;
|
||||
if this_multiview.get() > device.limits.max_multiview_view_count {
|
||||
return Err(RenderPassErrorInner::TooManyMultiviewViews);
|
||||
}
|
||||
}
|
||||
|
||||
detected_multiview = Some(this_multiview);
|
||||
@ -1389,7 +1405,20 @@ impl RenderPassInfo {
|
||||
}
|
||||
|
||||
let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
|
||||
let multiview = detected_multiview.expect("Multiview was not detected, no attachments");
|
||||
|
||||
let detected_multiview =
|
||||
detected_multiview.expect("Multiview was not detected, no attachments");
|
||||
if let Some(mask) = multiview_mask {
|
||||
// 0x01 will have msb 0
|
||||
let mask_msb = 31 - mask.leading_zeros();
|
||||
let detected_mv = detected_multiview.map(NonZeroU32::get).unwrap_or(1);
|
||||
if mask_msb >= detected_mv {
|
||||
return Err(RenderPassErrorInner::MultiViewMismatch);
|
||||
}
|
||||
if mask.get() != (1 << detected_mv) - 1 {
|
||||
device.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
|
||||
}
|
||||
}
|
||||
|
||||
let attachment_formats = AttachmentData {
|
||||
colors: color_attachments
|
||||
@ -1414,7 +1443,7 @@ impl RenderPassInfo {
|
||||
let context = RenderPassContext {
|
||||
attachments: attachment_formats,
|
||||
sample_count,
|
||||
multiview,
|
||||
multiview_mask,
|
||||
};
|
||||
|
||||
let timestamp_writes_hal = if let Some(tw) = timestamp_writes.as_ref() {
|
||||
@ -1450,7 +1479,7 @@ impl RenderPassInfo {
|
||||
sample_count,
|
||||
color_attachments: &color_attachments_hal,
|
||||
depth_stencil_attachment: depth_stencil,
|
||||
multiview,
|
||||
multiview_mask,
|
||||
timestamp_writes: timestamp_writes_hal,
|
||||
occlusion_query_set: occlusion_query_set_hal,
|
||||
};
|
||||
@ -1485,7 +1514,7 @@ impl RenderPassInfo {
|
||||
is_stencil_read_only,
|
||||
extent,
|
||||
divergent_discarded_depth_stencil_aspect,
|
||||
multiview,
|
||||
multiview_mask,
|
||||
})
|
||||
}
|
||||
|
||||
@ -1552,7 +1581,7 @@ impl RenderPassInfo {
|
||||
stencil_ops,
|
||||
clear_value: (0.0, 0),
|
||||
}),
|
||||
multiview: self.multiview,
|
||||
multiview_mask: self.multiview_mask,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
@ -1713,6 +1742,8 @@ impl Global {
|
||||
None
|
||||
};
|
||||
|
||||
arc_desc.multiview_mask = desc.multiview_mask;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1731,6 +1762,7 @@ impl Global {
|
||||
color_attachments: ArrayVec::new(),
|
||||
depth_stencil_attachment: None,
|
||||
occlusion_query_set: None,
|
||||
multiview_mask: None,
|
||||
};
|
||||
match fill_arc_desc(hub, desc, &mut arc_desc, &cmd_enc.device) {
|
||||
Ok(()) => (RenderPass::new(cmd_enc, arc_desc), None),
|
||||
@ -1816,6 +1848,7 @@ impl Global {
|
||||
depth_stencil_attachment: pass.depth_stencil_attachment.take(),
|
||||
timestamp_writes: pass.timestamp_writes.take(),
|
||||
occlusion_query_set: pass.occlusion_query_set.take(),
|
||||
multiview_mask: pass.multiview_mask,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1830,6 +1863,7 @@ pub(super) fn encode_render_pass(
|
||||
>,
|
||||
mut timestamp_writes: Option<ArcPassTimestampWrites>,
|
||||
occlusion_query_set: Option<Arc<QuerySet>>,
|
||||
multiview_mask: Option<NonZeroU32>,
|
||||
) -> Result<(), RenderPassError> {
|
||||
let pass_scope = PassErrorScope::Pass;
|
||||
|
||||
@ -1868,6 +1902,7 @@ pub(super) fn encode_render_pass(
|
||||
&mut pending_query_resets,
|
||||
&mut pending_discard_init_fixups,
|
||||
parent_state.snatch_guard,
|
||||
multiview_mask,
|
||||
)
|
||||
.map_pass_err(pass_scope)?;
|
||||
|
||||
@ -2561,6 +2596,26 @@ fn set_scissor(state: &mut State, rect: Rect<u32>) -> Result<(), RenderPassError
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_mesh_draw_multiview(state: &State) -> Result<(), RenderPassErrorInner> {
|
||||
if let Some(mv) = state.info.multiview_mask {
|
||||
let highest_bit = 31 - mv.leading_zeros();
|
||||
|
||||
let features = state.pass.base.device.features;
|
||||
|
||||
if !features.contains(wgt::Features::EXPERIMENTAL_MESH_SHADER_MULTIVIEW)
|
||||
|| highest_bit > state.pass.base.device.limits.max_mesh_multiview_view_count
|
||||
{
|
||||
return Err(RenderPassErrorInner::Draw(
|
||||
DrawError::MeshPipelineMultiviewLimitsViolated {
|
||||
highest_view_index: highest_bit,
|
||||
max_multiviews: state.pass.base.device.limits.max_mesh_multiview_view_count,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(
|
||||
state: &mut State,
|
||||
vertex_count: u32,
|
||||
@ -2645,7 +2700,9 @@ fn draw_mesh_tasks(
|
||||
api_log!("RenderPass::draw_mesh_tasks {group_count_x} {group_count_y} {group_count_z}");
|
||||
|
||||
state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
|
||||
|
||||
state.flush_bindings()?;
|
||||
validate_mesh_draw_multiview(state)?;
|
||||
|
||||
let groups_size_limit = state
|
||||
.pass
|
||||
@ -2696,6 +2753,10 @@ fn multi_draw_indirect(
|
||||
state.is_ready(family)?;
|
||||
state.flush_bindings()?;
|
||||
|
||||
if family == DrawCommandFamily::DrawMeshTasks {
|
||||
validate_mesh_draw_multiview(state)?;
|
||||
}
|
||||
|
||||
state
|
||||
.pass
|
||||
.base
|
||||
@ -2878,6 +2939,10 @@ fn multi_draw_indirect_count(
|
||||
state.is_ready(family)?;
|
||||
state.flush_bindings()?;
|
||||
|
||||
if family == DrawCommandFamily::DrawMeshTasks {
|
||||
validate_mesh_draw_multiview(state)?;
|
||||
}
|
||||
|
||||
let stride = get_stride_of_indirect_args(family);
|
||||
|
||||
state
|
||||
|
||||
@ -1478,7 +1478,7 @@ impl Global {
|
||||
depth_stencil: desc.depth_stencil.clone(),
|
||||
multisample: desc.multisample,
|
||||
fragment,
|
||||
multiview: desc.multiview,
|
||||
multiview_mask: desc.multiview_mask,
|
||||
cache,
|
||||
};
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ impl<T: PartialEq> Eq for AttachmentData<T> {}
|
||||
pub(crate) struct RenderPassContext {
|
||||
pub attachments: AttachmentData<TextureFormat>,
|
||||
pub sample_count: u32,
|
||||
pub multiview: Option<NonZeroU32>,
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
}
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
@ -144,10 +144,10 @@ impl RenderPassContext {
|
||||
res: res.error_ident(),
|
||||
});
|
||||
}
|
||||
if self.multiview != other.multiview {
|
||||
if self.multiview_mask != other.multiview_mask {
|
||||
return Err(RenderPassCompatibilityError::IncompatibleMultiview {
|
||||
expected: self.multiview,
|
||||
actual: other.multiview,
|
||||
expected: self.multiview_mask,
|
||||
actual: other.multiview_mask,
|
||||
res: res.error_ident(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -4442,8 +4442,11 @@ impl Device {
|
||||
};
|
||||
|
||||
// Multiview is only supported if the feature is enabled
|
||||
if desc.multiview.is_some() {
|
||||
if let Some(mv_mask) = desc.multiview_mask {
|
||||
self.require_features(wgt::Features::MULTIVIEW)?;
|
||||
if !(mv_mask.get() + 1).is_power_of_two() {
|
||||
self.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !self
|
||||
@ -4493,7 +4496,7 @@ impl Device {
|
||||
multisample: desc.multisample,
|
||||
fragment_stage,
|
||||
color_targets,
|
||||
multiview: desc.multiview,
|
||||
multiview_mask: desc.multiview_mask,
|
||||
cache: cache.as_ref().map(|it| it.raw()),
|
||||
};
|
||||
unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err(
|
||||
@ -4527,7 +4530,7 @@ impl Device {
|
||||
depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
|
||||
},
|
||||
sample_count: samples,
|
||||
multiview: desc.multiview,
|
||||
multiview_mask: desc.multiview_mask,
|
||||
};
|
||||
|
||||
let mut flags = pipeline::PipelineFlags::empty();
|
||||
|
||||
@ -39,7 +39,7 @@ pub(crate) fn new_render_bundle_encoder_descriptor(
|
||||
}
|
||||
}),
|
||||
sample_count: context.sample_count,
|
||||
multiview: context.multiview,
|
||||
multiview: context.multiview_mask,
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,12 +195,14 @@ impl IntoTrace for ArcCommand {
|
||||
depth_stencil_attachment,
|
||||
timestamp_writes,
|
||||
occlusion_query_set,
|
||||
multiview_mask,
|
||||
} => Command::RunRenderPass {
|
||||
pass: pass.into_trace(),
|
||||
color_attachments: color_attachments.into_trace(),
|
||||
depth_stencil_attachment: depth_stencil_attachment.map(|d| d.into_trace()),
|
||||
timestamp_writes: timestamp_writes.map(|tw| tw.into_trace()),
|
||||
occlusion_query_set: occlusion_query_set.map(|q| q.to_trace()),
|
||||
multiview_mask,
|
||||
},
|
||||
ArcCommand::BuildAccelerationStructures { blas, tlas } => {
|
||||
Command::BuildAccelerationStructures {
|
||||
@ -660,7 +662,7 @@ impl<'a> IntoTrace for crate::pipeline::ResolvedGeneralRenderPipelineDescriptor<
|
||||
depth_stencil: self.depth_stencil,
|
||||
multisample: self.multisample,
|
||||
fragment: self.fragment.map(|f| f.into_trace()),
|
||||
multiview: self.multiview,
|
||||
multiview_mask: self.multiview_mask,
|
||||
cache: self.cache.map(|c| c.into_trace()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,7 +467,7 @@ pub struct RenderPipelineDescriptor<
|
||||
pub fragment: Option<FragmentState<'a, SM>>,
|
||||
/// If the pipeline will be used with a multiview render pass, this indicates how many array
|
||||
/// layers the attachments will have.
|
||||
pub multiview: Option<NonZeroU32>,
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
/// The pipeline cache to use when creating this pipeline.
|
||||
pub cache: Option<PLC>,
|
||||
}
|
||||
@ -539,7 +539,7 @@ pub struct GeneralRenderPipelineDescriptor<
|
||||
pub fragment: Option<FragmentState<'a, SM>>,
|
||||
/// If the pipeline will be used with a multiview render pass, this indicates how many array
|
||||
/// layers the attachments will have.
|
||||
pub multiview: Option<NonZeroU32>,
|
||||
pub multiview_mask: Option<NonZeroU32>,
|
||||
/// The pipeline cache to use when creating this pipeline.
|
||||
pub cache: Option<PLC>,
|
||||
}
|
||||
@ -555,7 +555,7 @@ impl<'a, PLL, SM, PLC> From<RenderPipelineDescriptor<'a, PLL, SM, PLC>>
|
||||
depth_stencil: value.depth_stencil,
|
||||
multisample: value.multisample,
|
||||
fragment: value.fragment,
|
||||
multiview: value.multiview,
|
||||
multiview_mask: value.multiview_mask,
|
||||
cache: value.cache,
|
||||
}
|
||||
}
|
||||
@ -572,7 +572,7 @@ impl<'a, PLL, SM, PLC> From<MeshPipelineDescriptor<'a, PLL, SM, PLC>>
|
||||
depth_stencil: value.depth_stencil,
|
||||
multisample: value.multisample,
|
||||
fragment: value.fragment,
|
||||
multiview: value.multiview,
|
||||
multiview_mask: value.multiview,
|
||||
cache: value.cache,
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +84,7 @@ metal = [
|
||||
"dep:objc",
|
||||
"dep:parking_lot",
|
||||
"dep:profiling",
|
||||
"dep:smallvec",
|
||||
]
|
||||
vulkan = [
|
||||
"naga/spv-out",
|
||||
|
||||
@ -280,7 +280,7 @@ impl<A: hal::Api> Example<A> {
|
||||
blend: Some(wgpu_types::BlendState::ALPHA_BLENDING),
|
||||
write_mask: wgpu_types::ColorWrites::default(),
|
||||
})],
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
};
|
||||
let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() };
|
||||
@ -727,7 +727,7 @@ impl<A: hal::Api> Example<A> {
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
|
||||
@ -329,7 +329,7 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
|
||||
clear_value: wgpu_types::Color::BLUE,
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
multiview: None,
|
||||
multiview_mask: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user