mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-21 22:34:34 +00:00
example-runner-wgpu: enable debugPrintf
panic support via --force-spirv-passthru
.
This commit is contained in:
parent
9808cd0309
commit
24f42f2b42
@ -211,8 +211,6 @@ pub fn compile_shaders() -> Vec<SpvFile> {
|
||||
|
||||
SpirvBuilder::new("examples/shaders/sky-shader", "spirv-unknown-vulkan1.1")
|
||||
.print_metadata(MetadataPrintout::None)
|
||||
// HACK(eddyb) having the `ash` runner do this is the easiest way I found
|
||||
// to test this `panic!` feature with actual `debugPrintf` support.
|
||||
.shader_panic_strategy(spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
|
||||
print_inputs: true,
|
||||
print_backtrace: true,
|
||||
@ -380,10 +378,10 @@ impl RenderBase {
|
||||
};
|
||||
|
||||
let device: ash::Device = {
|
||||
let mut device_extension_names_raw = vec![khr::Swapchain::name().as_ptr()];
|
||||
if options.debug_layer {
|
||||
device_extension_names_raw.push(vk::KhrShaderNonSemanticInfoFn::name().as_ptr());
|
||||
}
|
||||
let device_extension_names_raw = [
|
||||
khr::Swapchain::name().as_ptr(),
|
||||
vk::KhrShaderNonSemanticInfoFn::name().as_ptr(),
|
||||
];
|
||||
let features = vk::PhysicalDeviceFeatures {
|
||||
shader_clip_distance: 1,
|
||||
..Default::default()
|
||||
|
@ -1,20 +1,17 @@
|
||||
use wgpu::util::DeviceExt;
|
||||
use crate::{maybe_watch, CompiledShaderModules, Options};
|
||||
|
||||
use super::Options;
|
||||
use std::{convert::TryInto, time::Duration};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
pub fn start(options: &Options) {
|
||||
env_logger::init();
|
||||
|
||||
let shader_binary = crate::maybe_watch(options.shader, None);
|
||||
let compiled_shader_modules = maybe_watch(options, None);
|
||||
|
||||
futures::executor::block_on(start_internal(options, shader_binary));
|
||||
futures::executor::block_on(start_internal(options, compiled_shader_modules));
|
||||
}
|
||||
|
||||
pub async fn start_internal(
|
||||
options: &Options,
|
||||
shader_binary: wgpu::ShaderModuleDescriptorSpirV<'static>,
|
||||
) {
|
||||
async fn start_internal(options: &Options, compiled_shader_modules: CompiledShaderModules) {
|
||||
let backends = wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::PRIMARY);
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends,
|
||||
@ -46,11 +43,14 @@ pub async fn start_internal(
|
||||
|
||||
let timestamp_period = queue.get_timestamp_period();
|
||||
|
||||
let entry_point = "main_cs";
|
||||
|
||||
// FIXME(eddyb) automate this decision by default.
|
||||
let module = compiled_shader_modules.spv_module_for_entry_point(entry_point);
|
||||
let module = if options.force_spirv_passthru {
|
||||
unsafe { device.create_shader_module_spirv(&shader_binary) }
|
||||
unsafe { device.create_shader_module_spirv(&module) }
|
||||
} else {
|
||||
let wgpu::ShaderModuleDescriptorSpirV { label, source } = shader_binary;
|
||||
let wgpu::ShaderModuleDescriptorSpirV { label, source } = module;
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label,
|
||||
source: wgpu::ShaderSource::SpirV(source),
|
||||
@ -89,7 +89,7 @@ pub async fn start_internal(
|
||||
label: None,
|
||||
layout: Some(&pipeline_layout),
|
||||
module: &module,
|
||||
entry_point: "main_cs",
|
||||
entry_point,
|
||||
});
|
||||
|
||||
let readback_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::maybe_watch;
|
||||
use crate::{maybe_watch, CompiledShaderModules, Options};
|
||||
|
||||
use super::Options;
|
||||
use shared::ShaderConstants;
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent},
|
||||
@ -34,9 +33,9 @@ fn mouse_button_index(button: MouseButton) -> usize {
|
||||
|
||||
async fn run(
|
||||
options: Options,
|
||||
event_loop: EventLoop<wgpu::ShaderModuleDescriptorSpirV<'static>>,
|
||||
event_loop: EventLoop<CompiledShaderModules>,
|
||||
window: Window,
|
||||
shader_binary: wgpu::ShaderModuleDescriptorSpirV<'static>,
|
||||
compiled_shader_modules: CompiledShaderModules,
|
||||
) {
|
||||
let backends = wgpu::util::backend_bits_from_env()
|
||||
.unwrap_or(wgpu::Backends::VULKAN | wgpu::Backends::METAL);
|
||||
@ -135,7 +134,7 @@ async fn run(
|
||||
|pending| pending.preferred_format,
|
||||
|(_, surface_config)| surface_config.format,
|
||||
),
|
||||
shader_binary,
|
||||
compiled_shader_modules,
|
||||
);
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
@ -336,24 +335,45 @@ fn create_pipeline(
|
||||
device: &wgpu::Device,
|
||||
pipeline_layout: &wgpu::PipelineLayout,
|
||||
surface_format: wgpu::TextureFormat,
|
||||
shader_binary: wgpu::ShaderModuleDescriptorSpirV<'_>,
|
||||
compiled_shader_modules: CompiledShaderModules,
|
||||
) -> wgpu::RenderPipeline {
|
||||
// FIXME(eddyb) automate this decision by default.
|
||||
let module = if options.force_spirv_passthru {
|
||||
unsafe { device.create_shader_module_spirv(&shader_binary) }
|
||||
} else {
|
||||
let wgpu::ShaderModuleDescriptorSpirV { label, source } = shader_binary;
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label,
|
||||
source: wgpu::ShaderSource::SpirV(source),
|
||||
})
|
||||
let create_module = |module| {
|
||||
if options.force_spirv_passthru {
|
||||
unsafe { device.create_shader_module_spirv(&module) }
|
||||
} else {
|
||||
let wgpu::ShaderModuleDescriptorSpirV { label, source } = module;
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label,
|
||||
source: wgpu::ShaderSource::SpirV(source),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let vs_entry_point = shaders::main_vs;
|
||||
let fs_entry_point = shaders::main_fs;
|
||||
|
||||
let vs_module_descr = compiled_shader_modules.spv_module_for_entry_point(vs_entry_point);
|
||||
let fs_module_descr = compiled_shader_modules.spv_module_for_entry_point(fs_entry_point);
|
||||
|
||||
// HACK(eddyb) avoid calling `device.create_shader_module` twice unnecessarily.
|
||||
let vs_fs_same_module = std::ptr::eq(&vs_module_descr.source[..], &fs_module_descr.source[..]);
|
||||
|
||||
let vs_module = &create_module(vs_module_descr);
|
||||
let fs_module;
|
||||
let fs_module = if vs_fs_same_module {
|
||||
vs_module
|
||||
} else {
|
||||
fs_module = create_module(fs_module_descr);
|
||||
&fs_module
|
||||
};
|
||||
|
||||
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: None,
|
||||
layout: Some(pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &module,
|
||||
entry_point: shaders::main_vs,
|
||||
module: vs_module,
|
||||
entry_point: vs_entry_point,
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
@ -372,8 +392,8 @@ fn create_pipeline(
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &module,
|
||||
entry_point: shaders::main_fs,
|
||||
module: fs_module,
|
||||
entry_point: fs_entry_point,
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: None,
|
||||
@ -410,7 +430,7 @@ pub fn start(
|
||||
|
||||
// Build the shader before we pop open a window, since it might take a while.
|
||||
let initial_shader = maybe_watch(
|
||||
options.shader,
|
||||
options,
|
||||
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
|
||||
{
|
||||
let proxy = event_loop.create_proxy();
|
||||
|
@ -70,6 +70,7 @@
|
||||
// crate-specific exceptions:
|
||||
// #![allow()]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use structopt::StructOpt;
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
@ -87,16 +88,45 @@ pub enum RustGPUShader {
|
||||
Mouse,
|
||||
}
|
||||
|
||||
struct CompiledShaderModules {
|
||||
named_spv_modules: Vec<(Option<String>, wgpu::ShaderModuleDescriptorSpirV<'static>)>,
|
||||
}
|
||||
|
||||
impl CompiledShaderModules {
|
||||
fn spv_module_for_entry_point<'a>(
|
||||
&'a self,
|
||||
wanted_entry: &str,
|
||||
) -> wgpu::ShaderModuleDescriptorSpirV<'a> {
|
||||
for (name, spv_module) in &self.named_spv_modules {
|
||||
match name {
|
||||
Some(name) if name != wanted_entry => continue,
|
||||
_ => {
|
||||
return wgpu::ShaderModuleDescriptorSpirV {
|
||||
label: name.as_deref(),
|
||||
source: Cow::Borrowed(&spv_module.source),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
unreachable!(
|
||||
"{wanted_entry:?} not found in modules {:?}",
|
||||
self.named_spv_modules
|
||||
.iter()
|
||||
.map(|(name, _)| name)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_watch(
|
||||
shader: RustGPUShader,
|
||||
options: &Options,
|
||||
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))] on_watch: Option<
|
||||
Box<dyn FnMut(wgpu::ShaderModuleDescriptorSpirV<'static>) + Send + 'static>,
|
||||
Box<dyn FnMut(CompiledShaderModules) + Send + 'static>,
|
||||
>,
|
||||
) -> wgpu::ShaderModuleDescriptorSpirV<'static> {
|
||||
) -> CompiledShaderModules {
|
||||
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
|
||||
{
|
||||
use spirv_builder::{CompileResult, MetadataPrintout, SpirvBuilder};
|
||||
use std::borrow::Cow;
|
||||
use std::path::PathBuf;
|
||||
// Hack: spirv_builder builds into a custom directory if running under cargo, to not
|
||||
// deadlock, and the default target directory if not. However, packages like `proc-macro2`
|
||||
@ -106,7 +136,7 @@ fn maybe_watch(
|
||||
// under cargo by setting these environment variables.
|
||||
std::env::set_var("OUT_DIR", env!("OUT_DIR"));
|
||||
std::env::set_var("PROFILE", env!("PROFILE"));
|
||||
let crate_name = match shader {
|
||||
let crate_name = match options.shader {
|
||||
RustGPUShader::Simplest => "simplest-shader",
|
||||
RustGPUShader::Sky => "sky-shader",
|
||||
RustGPUShader::Compute => "compute-shader",
|
||||
@ -117,8 +147,22 @@ fn maybe_watch(
|
||||
.iter()
|
||||
.copied()
|
||||
.collect::<PathBuf>();
|
||||
|
||||
let has_debug_printf = options.force_spirv_passthru;
|
||||
|
||||
let builder = SpirvBuilder::new(crate_path, "spirv-unknown-vulkan1.1")
|
||||
.print_metadata(MetadataPrintout::None);
|
||||
.print_metadata(MetadataPrintout::None)
|
||||
.shader_panic_strategy(if has_debug_printf {
|
||||
spirv_builder::ShaderPanicStrategy::DebugPrintfThenExit {
|
||||
print_inputs: true,
|
||||
print_backtrace: true,
|
||||
}
|
||||
} else {
|
||||
spirv_builder::ShaderPanicStrategy::SilentExit
|
||||
})
|
||||
// HACK(eddyb) needed because of `debugPrintf` instrumentation limitations
|
||||
// (see https://github.com/KhronosGroup/SPIRV-Tools/issues/4892).
|
||||
.multimodule(has_debug_printf);
|
||||
let initial_result = if let Some(mut f) = on_watch {
|
||||
builder
|
||||
.watch(move |compile_result| f(handle_compile_result(compile_result)))
|
||||
@ -126,17 +170,27 @@ fn maybe_watch(
|
||||
} else {
|
||||
builder.build().unwrap()
|
||||
};
|
||||
fn handle_compile_result(
|
||||
compile_result: CompileResult,
|
||||
) -> wgpu::ShaderModuleDescriptorSpirV<'static> {
|
||||
let module_path = compile_result.module.unwrap_single();
|
||||
let data = std::fs::read(module_path).unwrap();
|
||||
// FIXME(eddyb) this reallocates all the data pointlessly, there is
|
||||
// not a good reason to use `ShaderModuleDescriptorSpirV` specifically.
|
||||
let spirv = Cow::Owned(wgpu::util::make_spirv_raw(&data).into_owned());
|
||||
wgpu::ShaderModuleDescriptorSpirV {
|
||||
label: None,
|
||||
source: spirv,
|
||||
fn handle_compile_result(compile_result: CompileResult) -> CompiledShaderModules {
|
||||
let load_spv_module = |path| {
|
||||
let data = std::fs::read(path).unwrap();
|
||||
// FIXME(eddyb) this reallocates all the data pointlessly, there is
|
||||
// not a good reason to use `ShaderModuleDescriptorSpirV` specifically.
|
||||
let spirv = Cow::Owned(wgpu::util::make_spirv_raw(&data).into_owned());
|
||||
wgpu::ShaderModuleDescriptorSpirV {
|
||||
label: None,
|
||||
source: spirv,
|
||||
}
|
||||
};
|
||||
CompiledShaderModules {
|
||||
named_spv_modules: match compile_result.module {
|
||||
spirv_builder::ModuleResult::SingleModule(path) => {
|
||||
vec![(None, load_spv_module(path))]
|
||||
}
|
||||
spirv_builder::ModuleResult::MultiModule(modules) => modules
|
||||
.into_iter()
|
||||
.map(|(name, path)| (Some(name), load_spv_module(path)))
|
||||
.collect(),
|
||||
},
|
||||
}
|
||||
}
|
||||
handle_compile_result(initial_result)
|
||||
|
Loading…
Reference in New Issue
Block a user