From 88e83c52d46d2cb054c4867ec32326f77c2c5078 Mon Sep 17 00:00:00 2001 From: wicast Date: Thu, 10 Aug 2023 22:35:27 +0800 Subject: [PATCH] feat(spv): shader debug option --- deno_webgpu/shader.rs | 1 + examples/boids/src/main.rs | 2 ++ examples/bunnymark/src/main.rs | 1 + examples/conservative-raster/src/main.rs | 2 ++ examples/cube/src/main.rs | 1 + examples/hello-compute/src/main.rs | 1 + examples/hello-triangle/src/main.rs | 1 + examples/mipmap/src/main.rs | 2 ++ examples/msaa-line/src/main.rs | 1 + examples/shadow/src/main.rs | 1 + examples/skybox/src/main.rs | 1 + examples/stencil-triangles/src/main.rs | 1 + examples/timestamp-queries/src/main.rs | 1 + examples/water/src/main.rs | 2 ++ player/tests/data/bind-group.ron | 1 + .../tests/data/pipeline-statistics-query.ron | 1 + player/tests/data/quad.ron | 1 + player/tests/data/zero-init-buffer.ron | 1 + .../tests/data/zero-init-texture-binding.ron | 1 + tests/src/image.rs | 1 + tests/tests/occlusion_query/mod.rs | 1 + tests/tests/partially_bounded_arrays/mod.rs | 1 + tests/tests/shader/mod.rs | 1 + wgpu-core/src/device/resource.rs | 20 +++++++++++++++- wgpu-core/src/pipeline.rs | 1 + wgpu-hal/examples/halmark/main.rs | 1 + wgpu-hal/src/lib.rs | 8 +++++++ wgpu-hal/src/vulkan/device.rs | 20 +++++++++++++++- wgpu/src/backend/direct.rs | 2 ++ wgpu/src/lib.rs | 2 ++ wgpu/src/macros.rs | 23 ++++++++++++------- 31 files changed, 94 insertions(+), 10 deletions(-) diff --git a/deno_webgpu/shader.rs b/deno_webgpu/shader.rs index fb4f316926..60258d808b 100644 --- a/deno_webgpu/shader.rs +++ b/deno_webgpu/shader.rs @@ -43,6 +43,7 @@ pub fn op_webgpu_create_shader_module( let descriptor = wgpu_core::pipeline::ShaderModuleDescriptor { label: label.map(Cow::from), shader_bound_checks: wgpu_types::ShaderBoundChecks::default(), + debug: false, }; gfx_put!(device => instance.device_create_shader_module( diff --git a/examples/boids/src/main.rs b/examples/boids/src/main.rs index 357792de4f..7629073a0d 100644 --- a/examples/boids/src/main.rs +++ b/examples/boids/src/main.rs @@ -46,10 +46,12 @@ impl wgpu_example::framework::Example for Example { let compute_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("compute.wgsl"))), + debug: false, }); let draw_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("draw.wgsl"))), + debug: false, }); // buffer for simulation parameters uniform diff --git a/examples/bunnymark/src/main.rs b/examples/bunnymark/src/main.rs index 256083eebb..563d7b2373 100644 --- a/examples/bunnymark/src/main.rs +++ b/examples/bunnymark/src/main.rs @@ -48,6 +48,7 @@ impl wgpu_example::framework::Example for Example { source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!( "../../../wgpu-hal/examples/halmark/shader.wgsl" ))), + debug: false, }); let global_bind_group_layout = diff --git a/examples/conservative-raster/src/main.rs b/examples/conservative-raster/src/main.rs index e5cfb4d775..2fb2255981 100644 --- a/examples/conservative-raster/src/main.rs +++ b/examples/conservative-raster/src/main.rs @@ -88,6 +88,7 @@ impl wgpu_example::framework::Example for Example { source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!( "triangle_and_lines.wgsl" ))), + debug: false, }); let pipeline_triangle_conservative = @@ -197,6 +198,7 @@ impl wgpu_example::framework::Example for Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("upscale.wgsl"))), + debug: false, }); ( device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { diff --git a/examples/cube/src/main.rs b/examples/cube/src/main.rs index a10dfd0fd0..4e24864057 100644 --- a/examples/cube/src/main.rs +++ b/examples/cube/src/main.rs @@ -241,6 +241,7 @@ impl wgpu_example::framework::Example for Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let vertex_buffers = [wgpu::VertexBufferLayout { diff --git a/examples/hello-compute/src/main.rs b/examples/hello-compute/src/main.rs index 3b102f4e0e..3107752bbf 100644 --- a/examples/hello-compute/src/main.rs +++ b/examples/hello-compute/src/main.rs @@ -72,6 +72,7 @@ async fn execute_gpu_inner( let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); // Gets the size in bytes of the buffer. diff --git a/examples/hello-triangle/src/main.rs b/examples/hello-triangle/src/main.rs index c5432acd07..ebd68d61ec 100644 --- a/examples/hello-triangle/src/main.rs +++ b/examples/hello-triangle/src/main.rs @@ -40,6 +40,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { diff --git a/examples/mipmap/src/main.rs b/examples/mipmap/src/main.rs index d21f6c1e08..78512cba17 100644 --- a/examples/mipmap/src/main.rs +++ b/examples/mipmap/src/main.rs @@ -85,6 +85,7 @@ impl Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("blit.wgsl"))), + debug: false, }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { @@ -282,6 +283,7 @@ impl wgpu_example::framework::Example for Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("draw.wgsl"))), + debug: false, }); let draw_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { diff --git a/examples/msaa-line/src/main.rs b/examples/msaa-line/src/main.rs index 2f42817765..cf5d8232e1 100644 --- a/examples/msaa-line/src/main.rs +++ b/examples/msaa-line/src/main.rs @@ -151,6 +151,7 @@ impl wgpu_example::framework::Example for Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { diff --git a/examples/shadow/src/main.rs b/examples/shadow/src/main.rs index 09b0982ea9..eaa273b51d 100644 --- a/examples/shadow/src/main.rs +++ b/examples/shadow/src/main.rs @@ -451,6 +451,7 @@ impl wgpu_example::framework::Example for Example { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let shadow_pass = { diff --git a/examples/skybox/src/main.rs b/examples/skybox/src/main.rs index 9873ac9c0b..00d87b0fc3 100644 --- a/examples/skybox/src/main.rs +++ b/examples/skybox/src/main.rs @@ -171,6 +171,7 @@ impl wgpu_example::framework::Example for Skybox { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let camera = Camera { diff --git a/examples/stencil-triangles/src/main.rs b/examples/stencil-triangles/src/main.rs index 55aad9c9ba..38c7c9d6aa 100644 --- a/examples/stencil-triangles/src/main.rs +++ b/examples/stencil-triangles/src/main.rs @@ -56,6 +56,7 @@ impl wgpu_example::framework::Example for Triangles { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let vertex_buffers = [wgpu::VertexBufferLayout { diff --git a/examples/timestamp-queries/src/main.rs b/examples/timestamp-queries/src/main.rs index b28926c027..744fe7f8d8 100644 --- a/examples/timestamp-queries/src/main.rs +++ b/examples/timestamp-queries/src/main.rs @@ -234,6 +234,7 @@ fn submit_render_and_compute_pass_with_queries( let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); encoder.write_timestamp(&queries.set, queries.next_unused_query); diff --git a/examples/water/src/main.rs b/examples/water/src/main.rs index 5d5daa1f59..aef39016da 100644 --- a/examples/water/src/main.rs +++ b/examples/water/src/main.rs @@ -496,10 +496,12 @@ impl wgpu_example::framework::Example for Example { let terrain_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("terrain"), source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("terrain.wgsl"))), + debug: false, }); let water_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("water"), source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("water.wgsl"))), + debug: false, }); // Create the render pipelines. These describe how the data will flow through the GPU, and what diff --git a/player/tests/data/bind-group.ron b/player/tests/data/bind-group.ron index 00ecf0b20c..30da133d52 100644 --- a/player/tests/data/bind-group.ron +++ b/player/tests/data/bind-group.ron @@ -12,6 +12,7 @@ desc: ( label: None, flags: (bits: 3), + debug: false, ), data: "empty.wgsl", ), diff --git a/player/tests/data/pipeline-statistics-query.ron b/player/tests/data/pipeline-statistics-query.ron index 999c333a30..e549f3e578 100644 --- a/player/tests/data/pipeline-statistics-query.ron +++ b/player/tests/data/pipeline-statistics-query.ron @@ -19,6 +19,7 @@ desc: ( label: None, flags: (bits: 3), + debug: false, ), data: "empty.wgsl", ), diff --git a/player/tests/data/quad.ron b/player/tests/data/quad.ron index 563ba24b84..64d8bb36b7 100644 --- a/player/tests/data/quad.ron +++ b/player/tests/data/quad.ron @@ -14,6 +14,7 @@ desc: ( label: None, flags: (bits: 3), + debug: false, ), data: "quad.wgsl", ), diff --git a/player/tests/data/zero-init-buffer.ron b/player/tests/data/zero-init-buffer.ron index ca75c658fc..69da11ca07 100644 --- a/player/tests/data/zero-init-buffer.ron +++ b/player/tests/data/zero-init-buffer.ron @@ -79,6 +79,7 @@ desc: ( label: None, flags: (bits: 3), + debug: false, ), data: "zero-init-buffer-for-binding.wgsl", ), diff --git a/player/tests/data/zero-init-texture-binding.ron b/player/tests/data/zero-init-texture-binding.ron index e94255cfc3..e4c2c8a4d8 100644 --- a/player/tests/data/zero-init-texture-binding.ron +++ b/player/tests/data/zero-init-texture-binding.ron @@ -124,6 +124,7 @@ desc: ( label: None, flags: (bits: 3), + debug: false, ), data: "zero-init-texture-binding.wgsl", ), diff --git a/tests/src/image.rs b/tests/src/image.rs index 00aa78f660..6c7666650f 100644 --- a/tests/src/image.rs +++ b/tests/src/image.rs @@ -339,6 +339,7 @@ fn copy_via_compute( let sm = device.create_shader_module(ShaderModuleDescriptor { label: Some("shader copy_texture_to_buffer.wgsl"), source: ShaderSource::Wgsl(Cow::Borrowed(&processed_source)), + debug: false, }); let pipeline_copy = device.create_compute_pipeline(&ComputePipelineDescriptor { diff --git a/tests/tests/occlusion_query/mod.rs b/tests/tests/occlusion_query/mod.rs index eab0828e41..61b3eb81d4 100644 --- a/tests/tests/occlusion_query/mod.rs +++ b/tests/tests/occlusion_query/mod.rs @@ -27,6 +27,7 @@ fn occlusion_query() { .create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("Shader module"), source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let pipeline = ctx .device diff --git a/tests/tests/partially_bounded_arrays/mod.rs b/tests/tests/partially_bounded_arrays/mod.rs index 43844e456e..1be1b27a0d 100644 --- a/tests/tests/partially_bounded_arrays/mod.rs +++ b/tests/tests/partially_bounded_arrays/mod.rs @@ -58,6 +58,7 @@ fn partially_bounded_array() { let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: None, source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), + debug: false, }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { diff --git a/tests/tests/shader/mod.rs b/tests/tests/shader/mod.rs index 498c16c337..38811f8e52 100644 --- a/tests/tests/shader/mod.rs +++ b/tests/tests/shader/mod.rs @@ -288,6 +288,7 @@ fn shader_input_output_test( let sm = ctx.device.create_shader_module(ShaderModuleDescriptor { label: Some(&format!("shader {test_name}")), source: ShaderSource::Wgsl(Cow::Borrowed(&processed)), + debug: false, }); let pipeline = ctx diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 074170e562..93b8be35d4 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1276,6 +1276,19 @@ impl Device { .contains(wgt::DownlevelFlags::MULTISAMPLED_SHADING), ); + let debug_source = if desc.debug { + Some(hal::DebugSource { + file_name: Cow::Owned( + desc.label + .as_ref() + .map_or("shader".to_string(), |l| l.to_string()), + ), + source_code: Cow::Owned(source.clone()), + }) + } else { + None + }; + let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) .validate(&module) .map_err(|inner| { @@ -1286,7 +1299,12 @@ impl Device { }) })?; let interface = validation::Interface::new(&module, &info, self.limits.clone()); - let hal_shader = hal::ShaderInput::Naga(hal::NagaShader { module, info }); + + let hal_shader = hal::ShaderInput::Naga(hal::NagaShader { + module, + info, + debug_source, + }); let hal_desc = hal::ShaderModuleDescriptor { label: desc.label.borrow_option(), diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index da06b652ea..a3bff1799e 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -37,6 +37,7 @@ pub struct ShaderModuleDescriptor<'a> { pub label: Label<'a>, #[cfg_attr(feature = "serde", serde(default))] pub shader_bound_checks: wgt::ShaderBoundChecks, + pub debug: bool, } #[derive(Debug)] diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 21289b18e5..3a9383e670 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -159,6 +159,7 @@ impl Example { hal::NagaShader { module: Cow::Owned(module), info, + debug_source: None, } }; let shader_desc = hal::ShaderModuleDescriptor { diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 1248ee9030..14de48be37 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1058,6 +1058,8 @@ pub struct NagaShader { pub module: Cow<'static, naga::Module>, /// Analysis information of the module. pub info: naga::valid::ModuleInfo, + /// Source codes for debug + pub debug_source: Option, } // Custom implementation avoids the need to generate Debug impl code @@ -1080,6 +1082,12 @@ pub struct ShaderModuleDescriptor<'a> { pub runtime_checks: bool, } +#[derive(Debug, Clone)] +pub struct DebugSource { + pub file_name: Cow<'static, str>, + pub source_code: Cow<'static, str>, +} + /// Describes a programmable pipeline stage. #[derive(Debug)] pub struct ProgrammableStage<'a, A: Api> { diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index a69897a324..63ec8e2eab 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -723,7 +723,9 @@ impl super::Device { entry_point: stage.entry_point.to_string(), shader_stage: naga_stage, }; - let needs_temp_options = !runtime_checks || !binding_map.is_empty(); + let needs_temp_options = !runtime_checks + || !binding_map.is_empty() + || naga_shader.debug_source.is_some(); let mut temp_options; let options = if needs_temp_options { temp_options = self.naga_options.clone(); @@ -739,6 +741,14 @@ impl super::Device { if !binding_map.is_empty() { temp_options.binding_map = binding_map.clone(); } + + if let Some(ref debug) = naga_shader.debug_source { + temp_options.debug_info = Some(naga::back::spv::DebugInfo { + source_code: &debug.source_code, + file_name: &debug.file_name, + }) + } + &temp_options } else { &self.naga_options @@ -1523,6 +1533,14 @@ impl crate::Device for super::Device { }); } let mut naga_options = self.naga_options.clone(); + naga_options.debug_info = + naga_shader + .debug_source + .as_ref() + .map(|d| naga::back::spv::DebugInfo { + source_code: d.source_code.as_ref(), + file_name: d.file_name.as_ref(), + }); if !desc.runtime_checks { naga_options.bounds_check_policies = naga::proc::BoundsCheckPolicies { index: naga::proc::BoundsCheckPolicy::Unchecked, diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index fca1d80c3c..f20d149fc8 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -888,6 +888,7 @@ impl crate::Context for Context { let descriptor = wgc::pipeline::ShaderModuleDescriptor { label: desc.label.map(Borrowed), shader_bound_checks, + debug: desc.debug, }; let source = match desc.source { #[cfg(feature = "spirv")] @@ -951,6 +952,7 @@ impl crate::Context for Context { // Doesn't matter the value since spirv shaders aren't mutated to include // runtime checks shader_bound_checks: unsafe { wgt::ShaderBoundChecks::unchecked() }, + debug: false, }; let (id, error) = wgc::gfx_select!( device => global.device_create_shader_module_spirv(*device, &descriptor, Borrowed(&desc.source), ()) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 7674bcb69a..4967aa442a 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -567,6 +567,8 @@ pub struct ShaderModuleDescriptor<'a> { pub label: Label<'a>, /// Source code for the shader. pub source: ShaderSource<'a>, + /// Generate debug symbols, only available in spv-out + pub debug: bool, } static_assertions::assert_impl_all!(ShaderModuleDescriptor: Send, Sync); diff --git a/wgpu/src/macros.rs b/wgpu/src/macros.rs index fc3560e01c..2bc9138696 100644 --- a/wgpu/src/macros.rs +++ b/wgpu/src/macros.rs @@ -81,13 +81,20 @@ macro_rules! include_spirv_raw { /// Macro to load a WGSL module statically. #[macro_export] macro_rules! include_wgsl { - ($($token:tt)*) => { - { - //log::info!("including '{}'", $($token)*); - $crate::ShaderModuleDescriptor { - label: Some($($token)*), - source: $crate::ShaderSource::Wgsl(include_str!($($token)*).into()), - } + ($name:tt) => {{ + // log::info!("including '{}'", $name); + $crate::ShaderModuleDescriptor { + label: Some($name), + source: $crate::ShaderSource::Wgsl(include_str!($name).into()), + debug: false, } - }; + }}; + ($name:tt, $debug:tt) => {{ + // log::info!("including '{}', '{}'", $name, $debug); + $crate::ShaderModuleDescriptor { + label: Some($name), + source: $crate::ShaderSource::Wgsl(include_str!($name).into()), + debug: $debug, + } + }}; }