mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add support for occlusion queries (#3402)
Co-authored-by: Leo Kettmeir <crowlkats@toaxl.com> Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
This commit is contained in:
parent
5b4c6b8ae4
commit
494ae1a815
15
CHANGELOG.md
15
CHANGELOG.md
@ -40,6 +40,21 @@ Bottom level categories:
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Major changes
|
||||||
|
|
||||||
|
#### Occlusion Query Support
|
||||||
|
|
||||||
|
The `occlusion_query_set` value defines where the occlusion query results will be stored for this pass.
|
||||||
|
|
||||||
|
```diff
|
||||||
|
let render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
// ...
|
||||||
|
+ occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
By @Valaphee in [#3402](https://github.com/gfx-rs/wgpu/pull/3402)
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|
||||||
- Omit texture store bound checks since they are no-ops if out of bounds on all APIs. By @teoxoy in [#3975](https://github.com/gfx-rs/wgpu/pull/3975)
|
- Omit texture store bound checks since they are no-ops if out of bounds on all APIs. By @teoxoy in [#3975](https://github.com/gfx-rs/wgpu/pull/3975)
|
||||||
|
|||||||
@ -98,6 +98,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
|
|||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
color_attachments: Vec<Option<GpuRenderPassColorAttachment>>,
|
color_attachments: Vec<Option<GpuRenderPassColorAttachment>>,
|
||||||
depth_stencil_attachment: Option<GpuRenderPassDepthStencilAttachment>,
|
depth_stencil_attachment: Option<GpuRenderPassDepthStencilAttachment>,
|
||||||
|
occlusion_query_set: Option<ResourceId>,
|
||||||
) -> Result<WebGpuResult, AnyError> {
|
) -> Result<WebGpuResult, AnyError> {
|
||||||
let command_encoder_resource = state
|
let command_encoder_resource = state
|
||||||
.resource_table
|
.resource_table
|
||||||
@ -171,10 +172,16 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let occlusion_query_set_resource = occlusion_query_set
|
||||||
|
.map(|rid| state.resource_table.get::<super::WebGpuQuerySet>(rid))
|
||||||
|
.transpose()?
|
||||||
|
.map(|query_set| query_set.1);
|
||||||
|
|
||||||
let descriptor = wgpu_core::command::RenderPassDescriptor {
|
let descriptor = wgpu_core::command::RenderPassDescriptor {
|
||||||
label: label.map(Cow::from),
|
label: label.map(Cow::from),
|
||||||
color_attachments: Cow::from(color_attachments),
|
color_attachments: Cow::from(color_attachments),
|
||||||
depth_stencil_attachment: processed_depth_stencil_attachment.as_ref(),
|
depth_stencil_attachment: processed_depth_stencil_attachment.as_ref(),
|
||||||
|
occlusion_query_set: occlusion_query_set_resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_pass = wgpu_core::command::RenderPass::new(command_encoder_resource.1, &descriptor);
|
let render_pass = wgpu_core::command::RenderPass::new(command_encoder_resource.1, &descriptor);
|
||||||
|
|||||||
@ -114,6 +114,40 @@ pub fn op_webgpu_render_pass_set_stencil_reference(
|
|||||||
Ok(WebGpuResult::empty())
|
Ok(WebGpuResult::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[op]
|
||||||
|
pub fn op_webgpu_render_pass_begin_occlusion_query(
|
||||||
|
state: &mut OpState,
|
||||||
|
render_pass_rid: ResourceId,
|
||||||
|
query_index: u32,
|
||||||
|
) -> Result<WebGpuResult, AnyError> {
|
||||||
|
let render_pass_resource = state
|
||||||
|
.resource_table
|
||||||
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
|
||||||
|
wgpu_core::command::render_ffi::wgpu_render_pass_begin_occlusion_query(
|
||||||
|
&mut render_pass_resource.0.borrow_mut(),
|
||||||
|
query_index,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(WebGpuResult::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[op]
|
||||||
|
pub fn op_webgpu_render_pass_end_occlusion_query(
|
||||||
|
state: &mut OpState,
|
||||||
|
render_pass_rid: ResourceId,
|
||||||
|
) -> Result<WebGpuResult, AnyError> {
|
||||||
|
let render_pass_resource = state
|
||||||
|
.resource_table
|
||||||
|
.get::<WebGpuRenderPass>(render_pass_rid)?;
|
||||||
|
|
||||||
|
wgpu_core::command::render_ffi::wgpu_render_pass_end_occlusion_query(
|
||||||
|
&mut render_pass_resource.0.borrow_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(WebGpuResult::empty())
|
||||||
|
}
|
||||||
|
|
||||||
#[op]
|
#[op]
|
||||||
pub fn op_webgpu_render_pass_begin_pipeline_statistics_query(
|
pub fn op_webgpu_render_pass_begin_pipeline_statistics_query(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
|
|||||||
@ -981,6 +981,7 @@ dictionary GPURenderPassDescriptor
|
|||||||
: GPUObjectDescriptorBase {
|
: GPUObjectDescriptorBase {
|
||||||
required sequence<GPURenderPassColorAttachment?> colorAttachments;
|
required sequence<GPURenderPassColorAttachment?> colorAttachments;
|
||||||
GPURenderPassDepthStencilAttachment depthStencilAttachment;
|
GPURenderPassDepthStencilAttachment depthStencilAttachment;
|
||||||
|
GPUQuerySet occlusionQuerySet;
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary GPURenderPassColorAttachment {
|
dictionary GPURenderPassColorAttachment {
|
||||||
|
|||||||
@ -283,6 +283,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
label: None,
|
label: None,
|
||||||
color_attachments: &color_attachments,
|
color_attachments: &color_attachments,
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// get command encoder
|
// get command encoder
|
||||||
|
|||||||
@ -336,6 +336,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.pipeline);
|
rpass.set_pipeline(&self.pipeline);
|
||||||
rpass.set_bind_group(0, &self.global_group, &[]);
|
rpass.set_bind_group(0, &self.global_group, &[]);
|
||||||
|
|||||||
@ -104,6 +104,7 @@ async fn create_red_image_with_dimensions(
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Copy the data from the texture to the buffer
|
// Copy the data from the texture to the buffer
|
||||||
|
|||||||
@ -273,6 +273,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&self.pipeline_triangle_conservative);
|
rpass.set_pipeline(&self.pipeline_triangle_conservative);
|
||||||
@ -292,6 +293,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&self.pipeline_upscale);
|
rpass.set_pipeline(&self.pipeline_upscale);
|
||||||
|
|||||||
@ -379,6 +379,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.push_debug_group("Prepare data for draw.");
|
rpass.push_debug_group("Prepare data for draw.");
|
||||||
rpass.set_pipeline(&self.pipeline);
|
rpass.set_pipeline(&self.pipeline);
|
||||||
|
|||||||
@ -122,6 +122,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&render_pipeline);
|
rpass.set_pipeline(&render_pipeline);
|
||||||
rpass.draw(0..3, 0..1);
|
rpass.draw(0..3, 0..1);
|
||||||
|
|||||||
@ -135,6 +135,7 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Window, wgpu::Color)>) {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -167,6 +167,7 @@ impl Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
if let Some(ref query_sets) = query_sets {
|
if let Some(ref query_sets) = query_sets {
|
||||||
rpass.write_timestamp(&query_sets.timestamp, timestamp_query_index_base);
|
rpass.write_timestamp(&query_sets.timestamp, timestamp_query_index_base);
|
||||||
@ -492,6 +493,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.draw_pipeline);
|
rpass.set_pipeline(&self.draw_pipeline);
|
||||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||||
|
|||||||
@ -300,6 +300,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
label: None,
|
label: None,
|
||||||
color_attachments: &[Some(rpass_color_attachment)],
|
color_attachments: &[Some(rpass_color_attachment)],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
})
|
})
|
||||||
.execute_bundles(iter::once(&self.bundle));
|
.execute_bundles(iter::once(&self.bundle));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -777,6 +777,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
pass.set_pipeline(&self.shadow_pass.pipeline);
|
pass.set_pipeline(&self.shadow_pass.pipeline);
|
||||||
pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]);
|
pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]);
|
||||||
@ -819,6 +820,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
pass.set_pipeline(&self.forward_pass.pipeline);
|
pass.set_pipeline(&self.forward_pass.pipeline);
|
||||||
pass.set_bind_group(0, &self.forward_pass.bind_group, &[]);
|
pass.set_bind_group(0, &self.forward_pass.bind_group, &[]);
|
||||||
|
|||||||
@ -439,6 +439,7 @@ impl wgpu_example::framework::Example for Skybox {
|
|||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||||
|
|||||||
@ -211,6 +211,7 @@ impl wgpu_example::framework::Example for Triangles {
|
|||||||
store: true,
|
store: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_stencil_reference(1);
|
rpass.set_stencil_reference(1);
|
||||||
|
|||||||
@ -383,6 +383,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&self.pipeline);
|
rpass.set_pipeline(&self.pipeline);
|
||||||
|
|||||||
@ -752,6 +752,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.execute_bundles([&self.terrain_bundle]);
|
rpass.execute_bundles([&self.terrain_bundle]);
|
||||||
@ -777,6 +778,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
}),
|
}),
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.terrain_pipeline);
|
rpass.set_pipeline(&self.terrain_pipeline);
|
||||||
rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]);
|
rpass.set_bind_group(0, &self.terrain_normal_bind_group, &[]);
|
||||||
@ -801,6 +803,7 @@ impl wgpu_example::framework::Example for Example {
|
|||||||
depth_ops: None,
|
depth_ops: None,
|
||||||
stencil_ops: None,
|
stencil_ops: None,
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&self.water_pipeline);
|
rpass.set_pipeline(&self.water_pipeline);
|
||||||
|
|||||||
@ -129,12 +129,14 @@ impl GlobalPlay for wgc::global::Global<IdentityPassThroughFactory> {
|
|||||||
base,
|
base,
|
||||||
target_colors,
|
target_colors,
|
||||||
target_depth_stencil,
|
target_depth_stencil,
|
||||||
|
occlusion_query_set_id,
|
||||||
} => {
|
} => {
|
||||||
self.command_encoder_run_render_pass_impl::<A>(
|
self.command_encoder_run_render_pass_impl::<A>(
|
||||||
encoder,
|
encoder,
|
||||||
base.as_ref(),
|
base.as_ref(),
|
||||||
&target_colors,
|
&target_colors,
|
||||||
target_depth_stencil.as_ref(),
|
target_depth_stencil.as_ref(),
|
||||||
|
occlusion_query_set_id,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
127
tests/tests/occlusion_query/mod.rs
Normal file
127
tests/tests/occlusion_query/mod.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
use wgpu_test::{initialize_test, TestParameters};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn occlusion_query() {
|
||||||
|
initialize_test(TestParameters::default(), |ctx| {
|
||||||
|
// Create depth texture
|
||||||
|
let depth_texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: Some("Depth texture"),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
let depth_texture_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
// Setup pipeline using a simple shader with hardcoded vertices
|
||||||
|
let shader = ctx
|
||||||
|
.device
|
||||||
|
.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Shader module"),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
|
||||||
|
});
|
||||||
|
let pipeline = ctx
|
||||||
|
.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Pipeline"),
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[],
|
||||||
|
},
|
||||||
|
fragment: None,
|
||||||
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::Less,
|
||||||
|
stencil: wgpu::StencilState::default(),
|
||||||
|
bias: wgpu::DepthBiasState::default(),
|
||||||
|
}),
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create occlusion query set
|
||||||
|
let query_set = ctx.device.create_query_set(&wgpu::QuerySetDescriptor {
|
||||||
|
label: Some("Query set"),
|
||||||
|
ty: wgpu::QueryType::Occlusion,
|
||||||
|
count: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
|
{
|
||||||
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: Some("Render pass"),
|
||||||
|
color_attachments: &[],
|
||||||
|
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
|
||||||
|
view: &depth_texture_view,
|
||||||
|
depth_ops: Some(wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(1.0),
|
||||||
|
store: true,
|
||||||
|
}),
|
||||||
|
stencil_ops: None,
|
||||||
|
}),
|
||||||
|
occlusion_query_set: Some(&query_set),
|
||||||
|
});
|
||||||
|
render_pass.set_pipeline(&pipeline);
|
||||||
|
|
||||||
|
// Not occluded (z = 1.0, nothing drawn yet)
|
||||||
|
render_pass.begin_occlusion_query(0);
|
||||||
|
render_pass.draw(4..7, 0..1);
|
||||||
|
render_pass.end_occlusion_query();
|
||||||
|
|
||||||
|
// Not occluded (z = 0.0)
|
||||||
|
render_pass.begin_occlusion_query(1);
|
||||||
|
render_pass.draw(0..3, 0..1);
|
||||||
|
render_pass.end_occlusion_query();
|
||||||
|
|
||||||
|
// Occluded (z = 1.0)
|
||||||
|
render_pass.begin_occlusion_query(2);
|
||||||
|
render_pass.draw(4..7, 0..1);
|
||||||
|
render_pass.end_occlusion_query();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve query set to buffer
|
||||||
|
let query_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("Query buffer"),
|
||||||
|
size: std::mem::size_of::<u64>() as u64 * 3,
|
||||||
|
usage: wgpu::BufferUsages::QUERY_RESOLVE | wgpu::BufferUsages::COPY_SRC,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
encoder.resolve_query_set(&query_set, 0..3, &query_buffer, 0);
|
||||||
|
|
||||||
|
let mapping_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: Some("Mapping buffer"),
|
||||||
|
size: query_buffer.size(),
|
||||||
|
usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
encoder.copy_buffer_to_buffer(&query_buffer, 0, &mapping_buffer, 0, query_buffer.size());
|
||||||
|
|
||||||
|
ctx.queue.submit(Some(encoder.finish()));
|
||||||
|
|
||||||
|
mapping_buffer
|
||||||
|
.slice(..)
|
||||||
|
.map_async(wgpu::MapMode::Read, |_| ());
|
||||||
|
ctx.device.poll(wgpu::Maintain::Wait);
|
||||||
|
let query_buffer_view = mapping_buffer.slice(..).get_mapped_range();
|
||||||
|
let query_data: &[u64; 3] = bytemuck::from_bytes(&query_buffer_view);
|
||||||
|
|
||||||
|
// WebGPU only defines query results as zero/non-zero
|
||||||
|
assert_ne!(query_data[0], 0);
|
||||||
|
assert_ne!(query_data[1], 0);
|
||||||
|
assert_eq!(query_data[2], 0);
|
||||||
|
})
|
||||||
|
}
|
||||||
7
tests/tests/occlusion_query/shader.wgsl
Normal file
7
tests/tests/occlusion_query/shader.wgsl
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@vertex
|
||||||
|
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
|
||||||
|
let x = f32(i32(in_vertex_index & 3u) - 1);
|
||||||
|
let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
|
||||||
|
|
||||||
|
return vec4<f32>(x, y, f32(in_vertex_index & 4u) / 8.0, 1.0);
|
||||||
|
}
|
||||||
@ -144,6 +144,7 @@ fn pass_reset_vertex_buffer() {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
double_rpass.set_pipeline(&double_pipeline);
|
double_rpass.set_pipeline(&double_pipeline);
|
||||||
@ -177,6 +178,7 @@ fn pass_reset_vertex_buffer() {
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
single_rpass.set_pipeline(&single_pipeline);
|
single_rpass.set_pipeline(&single_pipeline);
|
||||||
|
|||||||
@ -13,6 +13,7 @@ mod encoder;
|
|||||||
mod example_wgsl;
|
mod example_wgsl;
|
||||||
mod external_texture;
|
mod external_texture;
|
||||||
mod instance;
|
mod instance;
|
||||||
|
mod occlusion_query;
|
||||||
mod partially_bounded_arrays;
|
mod partially_bounded_arrays;
|
||||||
mod poll;
|
mod poll;
|
||||||
mod queue_transfer;
|
mod queue_transfer;
|
||||||
|
|||||||
@ -79,6 +79,7 @@ fn scissor_test_impl(ctx: &TestingContext, scissor_rect: Rect, expected_data: [u
|
|||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
render_pass.set_pipeline(&pipeline);
|
render_pass.set_pipeline(&pipeline);
|
||||||
render_pass.set_scissor_rect(
|
render_pass.set_scissor_rect(
|
||||||
|
|||||||
@ -176,6 +176,7 @@ fn pulling_common(
|
|||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
{
|
{
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
|
||||||
@ -185,7 +186,7 @@ fn pulling_common(
|
|||||||
view: &color_view,
|
view: &color_view,
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
label: None,
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&pipeline);
|
rpass.set_pipeline(&pipeline);
|
||||||
|
|||||||
@ -130,13 +130,14 @@ fn reinterpret(
|
|||||||
.device
|
.device
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
ops: wgpu::Operations::default(),
|
ops: wgpu::Operations::default(),
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
view: &target_view,
|
view: &target_view,
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
label: None,
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&pipeline);
|
rpass.set_pipeline(&pipeline);
|
||||||
rpass.set_bind_group(0, &bind_group, &[]);
|
rpass.set_bind_group(0, &bind_group, &[]);
|
||||||
|
|||||||
@ -108,13 +108,14 @@ fn pulling_common(
|
|||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
|
|
||||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
ops: wgpu::Operations::default(),
|
ops: wgpu::Operations::default(),
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
view: &dummy,
|
view: &dummy,
|
||||||
})],
|
})],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
label: None,
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
rpass.set_pipeline(&pipeline);
|
rpass.set_pipeline(&pipeline);
|
||||||
|
|||||||
@ -154,6 +154,7 @@ impl<'ctx> TestCase<'ctx> {
|
|||||||
store: true,
|
store: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
ctx.queue.submit([encoder.finish()]);
|
ctx.queue.submit([encoder.finish()]);
|
||||||
} else {
|
} else {
|
||||||
@ -237,6 +238,7 @@ impl<'ctx> TestCase<'ctx> {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +262,7 @@ impl<'ctx> TestCase<'ctx> {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +286,7 @@ impl<'ctx> TestCase<'ctx> {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -637,6 +637,8 @@ impl RenderBundleEncoder {
|
|||||||
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
||||||
RenderCommand::PopDebugGroup => unimplemented!(),
|
RenderCommand::PopDebugGroup => unimplemented!(),
|
||||||
RenderCommand::WriteTimestamp { .. } // Must check the TIMESTAMP_QUERY_INSIDE_PASSES feature
|
RenderCommand::WriteTimestamp { .. } // Must check the TIMESTAMP_QUERY_INSIDE_PASSES feature
|
||||||
|
| RenderCommand::BeginOcclusionQuery { .. }
|
||||||
|
| RenderCommand::EndOcclusionQuery
|
||||||
| RenderCommand::BeginPipelineStatisticsQuery { .. }
|
| RenderCommand::BeginPipelineStatisticsQuery { .. }
|
||||||
| RenderCommand::EndPipelineStatisticsQuery => unimplemented!(),
|
| RenderCommand::EndPipelineStatisticsQuery => unimplemented!(),
|
||||||
RenderCommand::ExecuteBundle(_)
|
RenderCommand::ExecuteBundle(_)
|
||||||
@ -950,6 +952,8 @@ impl<A: HalApi> RenderBundle<A> {
|
|||||||
return Err(ExecutionError::Unimplemented("debug-markers"))
|
return Err(ExecutionError::Unimplemented("debug-markers"))
|
||||||
}
|
}
|
||||||
RenderCommand::WriteTimestamp { .. }
|
RenderCommand::WriteTimestamp { .. }
|
||||||
|
| RenderCommand::BeginOcclusionQuery { .. }
|
||||||
|
| RenderCommand::EndOcclusionQuery
|
||||||
| RenderCommand::BeginPipelineStatisticsQuery { .. }
|
| RenderCommand::BeginPipelineStatisticsQuery { .. }
|
||||||
| RenderCommand::EndPipelineStatisticsQuery => {
|
| RenderCommand::EndPipelineStatisticsQuery => {
|
||||||
return Err(ExecutionError::Unimplemented("queries"))
|
return Err(ExecutionError::Unimplemented("queries"))
|
||||||
|
|||||||
@ -243,6 +243,10 @@ pub enum RenderCommand {
|
|||||||
query_set_id: id::QuerySetId,
|
query_set_id: id::QuerySetId,
|
||||||
query_index: u32,
|
query_index: u32,
|
||||||
},
|
},
|
||||||
|
BeginOcclusionQuery {
|
||||||
|
query_index: u32,
|
||||||
|
},
|
||||||
|
EndOcclusionQuery,
|
||||||
BeginPipelineStatisticsQuery {
|
BeginPipelineStatisticsQuery {
|
||||||
query_set_id: id::QuerySetId,
|
query_set_id: id::QuerySetId,
|
||||||
query_index: u32,
|
query_index: u32,
|
||||||
|
|||||||
@ -592,6 +592,10 @@ pub enum PassErrorScope {
|
|||||||
QueryReset,
|
QueryReset,
|
||||||
#[error("In a write_timestamp command")]
|
#[error("In a write_timestamp command")]
|
||||||
WriteTimestamp,
|
WriteTimestamp,
|
||||||
|
#[error("In a begin_occlusion_query command")]
|
||||||
|
BeginOcclusionQuery,
|
||||||
|
#[error("In a end_occlusion_query command")]
|
||||||
|
EndOcclusionQuery,
|
||||||
#[error("In a begin_pipeline_statistics_query command")]
|
#[error("In a begin_pipeline_statistics_query command")]
|
||||||
BeginPipelineStatisticsQuery,
|
BeginPipelineStatisticsQuery,
|
||||||
#[error("In a end_pipeline_statistics_query command")]
|
#[error("In a end_pipeline_statistics_query command")]
|
||||||
|
|||||||
@ -240,6 +240,40 @@ impl<A: HalApi> QuerySet<A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn validate_and_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
raw_encoder: &mut A::CommandEncoder,
|
||||||
|
query_set_id: id::QuerySetId,
|
||||||
|
query_index: u32,
|
||||||
|
reset_state: Option<&mut QueryResetMap<A>>,
|
||||||
|
active_query: &mut Option<(id::QuerySetId, u32)>,
|
||||||
|
) -> Result<(), QueryUseError> {
|
||||||
|
let needs_reset = reset_state.is_none();
|
||||||
|
let query_set = self.validate_query(
|
||||||
|
query_set_id,
|
||||||
|
SimplifiedQueryType::Occlusion,
|
||||||
|
query_index,
|
||||||
|
reset_state,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some((_old_id, old_idx)) = active_query.replace((query_set_id, query_index)) {
|
||||||
|
return Err(QueryUseError::AlreadyStarted {
|
||||||
|
active_query_index: old_idx,
|
||||||
|
new_query_index: query_index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// If we don't have a reset state tracker which can defer resets, we must reset now.
|
||||||
|
if needs_reset {
|
||||||
|
raw_encoder.reset_queries(&self.raw, query_index..(query_index + 1));
|
||||||
|
}
|
||||||
|
raw_encoder.begin_query(query_set, query_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn validate_and_begin_pipeline_statistics_query(
|
pub(super) fn validate_and_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
raw_encoder: &mut A::CommandEncoder,
|
raw_encoder: &mut A::CommandEncoder,
|
||||||
@ -275,6 +309,23 @@ impl<A: HalApi> QuerySet<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn end_occlusion_query<A: HalApi>(
|
||||||
|
raw_encoder: &mut A::CommandEncoder,
|
||||||
|
storage: &Storage<QuerySet<A>, id::QuerySetId>,
|
||||||
|
active_query: &mut Option<(id::QuerySetId, u32)>,
|
||||||
|
) -> Result<(), QueryUseError> {
|
||||||
|
if let Some((query_set_id, query_index)) = active_query.take() {
|
||||||
|
// We can unwrap here as the validity was validated when the active query was set
|
||||||
|
let query_set = storage.get(query_set_id).unwrap();
|
||||||
|
|
||||||
|
unsafe { raw_encoder.end_query(&query_set.raw, query_index) };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(QueryUseError::AlreadyStopped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn end_pipeline_statistics_query<A: HalApi>(
|
pub(super) fn end_pipeline_statistics_query<A: HalApi>(
|
||||||
raw_encoder: &mut A::CommandEncoder,
|
raw_encoder: &mut A::CommandEncoder,
|
||||||
storage: &Storage<QuerySet<A>, id::QuerySetId>,
|
storage: &Storage<QuerySet<A>, id::QuerySetId>,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use crate::{
|
|||||||
command::{
|
command::{
|
||||||
self,
|
self,
|
||||||
bind::Binder,
|
bind::Binder,
|
||||||
end_pipeline_statistics_query,
|
end_occlusion_query, end_pipeline_statistics_query,
|
||||||
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
||||||
BasePass, BasePassRef, BindGroupStateChange, CommandBuffer, CommandEncoderError,
|
BasePass, BasePassRef, BindGroupStateChange, CommandBuffer, CommandEncoderError,
|
||||||
CommandEncoderStatus, DrawError, ExecutionError, MapPassErr, PassErrorScope, QueryResetMap,
|
CommandEncoderStatus, DrawError, ExecutionError, MapPassErr, PassErrorScope, QueryResetMap,
|
||||||
@ -187,6 +187,8 @@ pub struct RenderPassDescriptor<'a> {
|
|||||||
pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
|
pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
|
||||||
/// The depth and stencil attachment of the render pass, if any.
|
/// The depth and stencil attachment of the render pass, if any.
|
||||||
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>,
|
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>,
|
||||||
|
/// Defines where the occlusion query results will be stored for this pass.
|
||||||
|
pub occlusion_query_set: Option<id::QuerySetId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "serial-pass", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "serial-pass", derive(Deserialize, Serialize))]
|
||||||
@ -195,6 +197,7 @@ pub struct RenderPass {
|
|||||||
parent_id: id::CommandEncoderId,
|
parent_id: id::CommandEncoderId,
|
||||||
color_targets: ArrayVec<Option<RenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
|
color_targets: ArrayVec<Option<RenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
|
||||||
depth_stencil_target: Option<RenderPassDepthStencilAttachment>,
|
depth_stencil_target: Option<RenderPassDepthStencilAttachment>,
|
||||||
|
occlusion_query_set_id: Option<id::QuerySetId>,
|
||||||
|
|
||||||
// Resource binding dedupe state.
|
// Resource binding dedupe state.
|
||||||
#[cfg_attr(feature = "serial-pass", serde(skip))]
|
#[cfg_attr(feature = "serial-pass", serde(skip))]
|
||||||
@ -210,6 +213,7 @@ impl RenderPass {
|
|||||||
parent_id,
|
parent_id,
|
||||||
color_targets: desc.color_attachments.iter().cloned().collect(),
|
color_targets: desc.color_attachments.iter().cloned().collect(),
|
||||||
depth_stencil_target: desc.depth_stencil_attachment.cloned(),
|
depth_stencil_target: desc.depth_stencil_attachment.cloned(),
|
||||||
|
occlusion_query_set_id: desc.occlusion_query_set,
|
||||||
|
|
||||||
current_bind_groups: BindGroupStateChange::new(),
|
current_bind_groups: BindGroupStateChange::new(),
|
||||||
current_pipeline: StateChange::new(),
|
current_pipeline: StateChange::new(),
|
||||||
@ -226,6 +230,7 @@ impl RenderPass {
|
|||||||
base: self.base,
|
base: self.base,
|
||||||
target_colors: self.color_targets.into_iter().collect(),
|
target_colors: self.color_targets.into_iter().collect(),
|
||||||
target_depth_stencil: self.depth_stencil_target,
|
target_depth_stencil: self.depth_stencil_target,
|
||||||
|
occlusion_query_set_id: self.occlusion_query_set_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,6 +594,8 @@ pub enum RenderPassErrorInner {
|
|||||||
"Multiview pass texture views with more than one array layer must have D2Array dimension"
|
"Multiview pass texture views with more than one array layer must have D2Array dimension"
|
||||||
)]
|
)]
|
||||||
MultiViewDimensionMismatch,
|
MultiViewDimensionMismatch,
|
||||||
|
#[error("missing occlusion query set")]
|
||||||
|
MissingOcclusionQuerySet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyError for RenderPassErrorInner {
|
impl PrettyError for RenderPassErrorInner {
|
||||||
@ -1201,6 +1208,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
pass.base.as_ref(),
|
pass.base.as_ref(),
|
||||||
&pass.color_targets,
|
&pass.color_targets,
|
||||||
pass.depth_stencil_target.as_ref(),
|
pass.depth_stencil_target.as_ref(),
|
||||||
|
pass.occlusion_query_set_id,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1211,6 +1219,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
base: BasePassRef<RenderCommand>,
|
base: BasePassRef<RenderCommand>,
|
||||||
color_attachments: &[Option<RenderPassColorAttachment>],
|
color_attachments: &[Option<RenderPassColorAttachment>],
|
||||||
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
|
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
|
||||||
|
occlusion_query_set_id: Option<id::QuerySetId>,
|
||||||
) -> Result<(), RenderPassError> {
|
) -> Result<(), RenderPassError> {
|
||||||
profiling::scope!("CommandEncoder::run_render_pass");
|
profiling::scope!("CommandEncoder::run_render_pass");
|
||||||
let init_scope = PassErrorScope::Pass(encoder_id);
|
let init_scope = PassErrorScope::Pass(encoder_id);
|
||||||
@ -1241,6 +1250,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
base: BasePass::from_ref(base),
|
base: BasePass::from_ref(base),
|
||||||
target_colors: color_attachments.to_vec(),
|
target_colors: color_attachments.to_vec(),
|
||||||
target_depth_stencil: depth_stencil_attachment.cloned(),
|
target_depth_stencil: depth_stencil_attachment.cloned(),
|
||||||
|
occlusion_query_set_id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2027,6 +2037,35 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
)
|
)
|
||||||
.map_pass_err(scope)?;
|
.map_pass_err(scope)?;
|
||||||
}
|
}
|
||||||
|
RenderCommand::BeginOcclusionQuery { query_index } => {
|
||||||
|
let scope = PassErrorScope::BeginOcclusionQuery;
|
||||||
|
|
||||||
|
let query_set_id = occlusion_query_set_id
|
||||||
|
.ok_or(RenderPassErrorInner::MissingOcclusionQuerySet)
|
||||||
|
.map_pass_err(scope)?;
|
||||||
|
let query_set: &resource::QuerySet<A> = cmd_buf
|
||||||
|
.trackers
|
||||||
|
.query_sets
|
||||||
|
.add_single(&*query_set_guard, query_set_id)
|
||||||
|
.ok_or(RenderCommandError::InvalidQuerySet(query_set_id))
|
||||||
|
.map_pass_err(scope)?;
|
||||||
|
|
||||||
|
query_set
|
||||||
|
.validate_and_begin_occlusion_query(
|
||||||
|
raw,
|
||||||
|
query_set_id,
|
||||||
|
query_index,
|
||||||
|
Some(&mut query_reset_state),
|
||||||
|
&mut active_query,
|
||||||
|
)
|
||||||
|
.map_pass_err(scope)?;
|
||||||
|
}
|
||||||
|
RenderCommand::EndOcclusionQuery => {
|
||||||
|
let scope = PassErrorScope::EndOcclusionQuery;
|
||||||
|
|
||||||
|
end_occlusion_query(raw, &*query_set_guard, &mut active_query)
|
||||||
|
.map_pass_err(scope)?;
|
||||||
|
}
|
||||||
RenderCommand::BeginPipelineStatisticsQuery {
|
RenderCommand::BeginPipelineStatisticsQuery {
|
||||||
query_set_id,
|
query_set_id,
|
||||||
query_index,
|
query_index,
|
||||||
@ -2544,6 +2583,21 @@ pub mod render_ffi {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wgpu_render_pass_begin_occlusion_query(
|
||||||
|
pass: &mut RenderPass,
|
||||||
|
query_index: u32,
|
||||||
|
) {
|
||||||
|
pass.base
|
||||||
|
.commands
|
||||||
|
.push(RenderCommand::BeginOcclusionQuery { query_index });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wgpu_render_pass_end_occlusion_query(pass: &mut RenderPass) {
|
||||||
|
pass.base.commands.push(RenderCommand::EndOcclusionQuery);
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wgpu_render_pass_begin_pipeline_statistics_query(
|
pub extern "C" fn wgpu_render_pass_begin_pipeline_statistics_query(
|
||||||
pass: &mut RenderPass,
|
pass: &mut RenderPass,
|
||||||
|
|||||||
@ -95,6 +95,10 @@ pub fn map_buffer_usage(usage: wgt::BufferUsages) -> hal::BufferUses {
|
|||||||
hal::BufferUses::INDIRECT,
|
hal::BufferUses::INDIRECT,
|
||||||
usage.contains(wgt::BufferUsages::INDIRECT),
|
usage.contains(wgt::BufferUsages::INDIRECT),
|
||||||
);
|
);
|
||||||
|
u.set(
|
||||||
|
hal::BufferUses::QUERY_RESOLVE,
|
||||||
|
usage.contains(wgt::BufferUsages::QUERY_RESOLVE),
|
||||||
|
);
|
||||||
u
|
u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -181,6 +181,7 @@ pub enum Command {
|
|||||||
base: crate::command::BasePass<crate::command::RenderCommand>,
|
base: crate::command::BasePass<crate::command::RenderCommand>,
|
||||||
target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
|
target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
|
||||||
target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
|
target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
|
||||||
|
occlusion_query_set_id: Option<id::QuerySetId>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -527,6 +527,10 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
map_flags |= glow::MAP_COHERENT_BIT;
|
map_flags |= glow::MAP_COHERENT_BIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: may also be required for other calls involving `buffer_sub_data_u8_slice` (e.g. copy buffer to buffer and clear buffer)
|
||||||
|
if desc.usage.intersects(crate::BufferUses::QUERY_RESOLVE) {
|
||||||
|
map_flags |= glow::DYNAMIC_STORAGE_BIT;
|
||||||
|
}
|
||||||
unsafe { gl.buffer_storage(target, raw_size, None, map_flags) };
|
unsafe { gl.buffer_storage(target, raw_size, None, map_flags) };
|
||||||
} else {
|
} else {
|
||||||
assert!(!is_coherent);
|
assert!(!is_coherent);
|
||||||
@ -1238,7 +1242,7 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
Ok(super::QuerySet {
|
Ok(super::QuerySet {
|
||||||
queries: queries.into_boxed_slice(),
|
queries: queries.into_boxed_slice(),
|
||||||
target: match desc.ty {
|
target: match desc.ty {
|
||||||
wgt::QueryType::Occlusion => glow::ANY_SAMPLES_PASSED,
|
wgt::QueryType::Occlusion => glow::ANY_SAMPLES_PASSED_CONSERVATIVE,
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@ -718,6 +718,8 @@ bitflags::bitflags! {
|
|||||||
const STORAGE_READ_WRITE = 1 << 8;
|
const STORAGE_READ_WRITE = 1 << 8;
|
||||||
/// The indirect or count buffer in a indirect draw or dispatch.
|
/// The indirect or count buffer in a indirect draw or dispatch.
|
||||||
const INDIRECT = 1 << 9;
|
const INDIRECT = 1 << 9;
|
||||||
|
/// A buffer used to store query results.
|
||||||
|
const QUERY_RESOLVE = 1 << 10;
|
||||||
/// The combination of states that a buffer may be in _at the same time_.
|
/// The combination of states that a buffer may be in _at the same time_.
|
||||||
const INCLUSIVE = Self::MAP_READ.bits() | Self::COPY_SRC.bits() |
|
const INCLUSIVE = Self::MAP_READ.bits() | Self::COPY_SRC.bits() |
|
||||||
Self::INDEX.bits() | Self::VERTEX.bits() | Self::UNIFORM.bits() |
|
Self::INDEX.bits() | Self::VERTEX.bits() | Self::UNIFORM.bits() |
|
||||||
|
|||||||
@ -1926,6 +1926,9 @@ impl crate::Context for Context {
|
|||||||
label: desc.label.map(Borrowed),
|
label: desc.label.map(Borrowed),
|
||||||
color_attachments: Borrowed(&colors),
|
color_attachments: Borrowed(&colors),
|
||||||
depth_stencil_attachment: depth_stencil.as_ref(),
|
depth_stencil_attachment: depth_stencil.as_ref(),
|
||||||
|
occlusion_query_set: desc
|
||||||
|
.occlusion_query_set
|
||||||
|
.map(|query_set| query_set.id.into()),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -2940,6 +2943,23 @@ impl crate::Context for Context {
|
|||||||
wgpu_render_pass_write_timestamp(pass_data, *query_set, query_index)
|
wgpu_render_pass_write_timestamp(pass_data, *query_set, query_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_pass_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
_pass: &mut Self::RenderPassId,
|
||||||
|
pass_data: &mut Self::RenderPassData,
|
||||||
|
query_index: u32,
|
||||||
|
) {
|
||||||
|
wgpu_render_pass_begin_occlusion_query(pass_data, query_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_pass_end_occlusion_query(
|
||||||
|
&self,
|
||||||
|
_pass: &mut Self::RenderPassId,
|
||||||
|
pass_data: &mut Self::RenderPassData,
|
||||||
|
) {
|
||||||
|
wgpu_render_pass_end_occlusion_query(pass_data)
|
||||||
|
}
|
||||||
|
|
||||||
fn render_pass_begin_pipeline_statistics_query(
|
fn render_pass_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
_pass: &mut Self::RenderPassId,
|
_pass: &mut Self::RenderPassId,
|
||||||
|
|||||||
@ -3217,6 +3217,23 @@ impl crate::context::Context for Context {
|
|||||||
panic!("TIMESTAMP_QUERY_INSIDE_PASSES feature must be enabled to call write_timestamp in a compute pass")
|
panic!("TIMESTAMP_QUERY_INSIDE_PASSES feature must be enabled to call write_timestamp in a compute pass")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_pass_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
_pass: &mut Self::RenderPassId,
|
||||||
|
_pass_data: &mut Self::RenderPassData,
|
||||||
|
_query_index: u32,
|
||||||
|
) {
|
||||||
|
// Not available in gecko yet
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_pass_end_occlusion_query(
|
||||||
|
&self,
|
||||||
|
_pass: &mut Self::RenderPassId,
|
||||||
|
_pass_data: &mut Self::RenderPassData,
|
||||||
|
) {
|
||||||
|
// Not available in gecko yet
|
||||||
|
}
|
||||||
|
|
||||||
fn render_pass_begin_pipeline_statistics_query(
|
fn render_pass_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
_pass: &mut Self::RenderPassId,
|
_pass: &mut Self::RenderPassId,
|
||||||
|
|||||||
@ -970,6 +970,17 @@ pub trait Context: Debug + WasmNotSend + WasmNotSync + Sized {
|
|||||||
query_set_data: &Self::QuerySetData,
|
query_set_data: &Self::QuerySetData,
|
||||||
query_index: u32,
|
query_index: u32,
|
||||||
);
|
);
|
||||||
|
fn render_pass_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
pass: &mut Self::RenderPassId,
|
||||||
|
pass_data: &mut Self::RenderPassData,
|
||||||
|
query_index: u32,
|
||||||
|
);
|
||||||
|
fn render_pass_end_occlusion_query(
|
||||||
|
&self,
|
||||||
|
pass: &mut Self::RenderPassId,
|
||||||
|
pass_data: &mut Self::RenderPassData,
|
||||||
|
);
|
||||||
fn render_pass_begin_pipeline_statistics_query(
|
fn render_pass_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
pass: &mut Self::RenderPassId,
|
pass: &mut Self::RenderPassId,
|
||||||
@ -1986,6 +1997,13 @@ pub(crate) trait DynContext: Debug + WasmNotSend + WasmNotSync {
|
|||||||
query_set_data: &crate::Data,
|
query_set_data: &crate::Data,
|
||||||
query_index: u32,
|
query_index: u32,
|
||||||
);
|
);
|
||||||
|
fn render_pass_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
pass: &mut ObjectId,
|
||||||
|
pass_data: &mut crate::Data,
|
||||||
|
query_index: u32,
|
||||||
|
);
|
||||||
|
fn render_pass_end_occlusion_query(&self, pass: &mut ObjectId, pass_data: &mut crate::Data);
|
||||||
fn render_pass_begin_pipeline_statistics_query(
|
fn render_pass_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
pass: &mut ObjectId,
|
pass: &mut ObjectId,
|
||||||
@ -3911,6 +3929,23 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_pass_begin_occlusion_query(
|
||||||
|
&self,
|
||||||
|
pass: &mut ObjectId,
|
||||||
|
pass_data: &mut crate::Data,
|
||||||
|
query_index: u32,
|
||||||
|
) {
|
||||||
|
let mut pass = <T::RenderPassId>::from(*pass);
|
||||||
|
let pass_data = downcast_mut::<T::RenderPassData>(pass_data);
|
||||||
|
Context::render_pass_begin_occlusion_query(self, &mut pass, pass_data, query_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_pass_end_occlusion_query(&self, pass: &mut ObjectId, pass_data: &mut crate::Data) {
|
||||||
|
let mut pass = <T::RenderPassId>::from(*pass);
|
||||||
|
let pass_data = downcast_mut::<T::RenderPassData>(pass_data);
|
||||||
|
Context::render_pass_end_occlusion_query(self, &mut pass, pass_data)
|
||||||
|
}
|
||||||
|
|
||||||
fn render_pass_begin_pipeline_statistics_query(
|
fn render_pass_begin_pipeline_statistics_query(
|
||||||
&self,
|
&self,
|
||||||
pass: &mut ObjectId,
|
pass: &mut ObjectId,
|
||||||
|
|||||||
@ -851,6 +851,7 @@ impl Drop for RenderBundle {
|
|||||||
/// It can be created with [`Device::create_query_set`].
|
/// It can be created with [`Device::create_query_set`].
|
||||||
///
|
///
|
||||||
/// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset).
|
/// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset).
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct QuerySet {
|
pub struct QuerySet {
|
||||||
context: Arc<C>,
|
context: Arc<C>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
@ -1336,6 +1337,8 @@ pub struct RenderPassDescriptor<'tex, 'desc> {
|
|||||||
pub color_attachments: &'desc [Option<RenderPassColorAttachment<'tex>>],
|
pub color_attachments: &'desc [Option<RenderPassColorAttachment<'tex>>],
|
||||||
/// The depth and stencil attachment of the render pass, if any.
|
/// The depth and stencil attachment of the render pass, if any.
|
||||||
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'tex>>,
|
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'tex>>,
|
||||||
|
/// Defines where the occlusion query results will be stored for this pass.
|
||||||
|
pub occlusion_query_set: Option<&'tex QuerySet>,
|
||||||
}
|
}
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
not(target_arch = "wasm32"),
|
not(target_arch = "wasm32"),
|
||||||
@ -3818,6 +3821,29 @@ impl<'a> RenderPass<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> RenderPass<'a> {
|
||||||
|
/// Start a occlusion query on this render pass. It can be ended with
|
||||||
|
/// `end_occlusion_query`. Occlusion queries may not be nested.
|
||||||
|
pub fn begin_occlusion_query(&mut self, query_index: u32) {
|
||||||
|
DynContext::render_pass_begin_occlusion_query(
|
||||||
|
&*self.parent.context,
|
||||||
|
&mut self.id,
|
||||||
|
self.data.as_mut(),
|
||||||
|
query_index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// End the occlusion query on this render pass. It can be started with
|
||||||
|
/// `begin_occlusion_query`. Occlusion queries may not be nested.
|
||||||
|
pub fn end_occlusion_query(&mut self) {
|
||||||
|
DynContext::render_pass_end_occlusion_query(
|
||||||
|
&*self.parent.context,
|
||||||
|
&mut self.id,
|
||||||
|
self.data.as_mut(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
|
/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
|
||||||
impl<'a> RenderPass<'a> {
|
impl<'a> RenderPass<'a> {
|
||||||
/// Start a pipeline statistics query on this render pass. It can be ended with
|
/// Start a pipeline statistics query on this render pass. It can be ended with
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user