mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Co-authored-by: Andreas Reich <r_andreas2@web.de> Co-authored-by: Magnus <85136135+SupaMaggie70Incorporated@users.noreply.github.com>
182 lines
6.2 KiB
Rust
182 lines
6.2 KiB
Rust
use std::process::Stdio;
|
|
|
|
// Same as in mesh shader tests
|
|
fn compile_glsl(device: &wgpu::Device, shader_stage: &'static str) -> wgpu::ShaderModule {
|
|
let cmd = std::process::Command::new("glslc")
|
|
.args([
|
|
&format!(
|
|
"{}/src/mesh_shader/shader.{shader_stage}",
|
|
env!("CARGO_MANIFEST_DIR")
|
|
),
|
|
"-o",
|
|
"-",
|
|
"--target-env=vulkan1.2",
|
|
"--target-spv=spv1.4",
|
|
])
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.spawn()
|
|
.expect("Failed to call glslc");
|
|
let output = cmd.wait_with_output().expect("Error waiting for glslc");
|
|
assert!(output.status.success());
|
|
unsafe {
|
|
device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
|
|
entry_point: "main".into(),
|
|
label: None,
|
|
spirv: Some(wgpu::util::make_spirv_raw(&output.stdout)),
|
|
..Default::default()
|
|
})
|
|
}
|
|
}
|
|
fn compile_hlsl(device: &wgpu::Device, entry: &str, stage_str: &str) -> wgpu::ShaderModule {
|
|
let out_path = format!(
|
|
"{}/src/mesh_shader/shader.{stage_str}.cso",
|
|
env!("CARGO_MANIFEST_DIR")
|
|
);
|
|
let cmd = std::process::Command::new("dxc")
|
|
.args([
|
|
"-T",
|
|
&format!("{stage_str}_6_5"),
|
|
"-E",
|
|
entry,
|
|
&format!("{}/src/mesh_shader/shader.hlsl", env!("CARGO_MANIFEST_DIR")),
|
|
"-Fo",
|
|
&out_path,
|
|
])
|
|
.output()
|
|
.unwrap();
|
|
if !cmd.status.success() {
|
|
panic!("DXC failed:\n{}", String::from_utf8(cmd.stderr).unwrap());
|
|
}
|
|
let file = std::fs::read(&out_path).unwrap();
|
|
std::fs::remove_file(out_path).unwrap();
|
|
unsafe {
|
|
device.create_shader_module_passthrough(wgpu::ShaderModuleDescriptorPassthrough {
|
|
entry_point: entry.to_owned(),
|
|
label: None,
|
|
num_workgroups: (1, 1, 1),
|
|
dxil: Some(std::borrow::Cow::Owned(file)),
|
|
..Default::default()
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct Example {
|
|
pipeline: wgpu::RenderPipeline,
|
|
}
|
|
impl crate::framework::Example for Example {
|
|
fn init(
|
|
config: &wgpu::SurfaceConfiguration,
|
|
adapter: &wgpu::Adapter,
|
|
device: &wgpu::Device,
|
|
_queue: &wgpu::Queue,
|
|
) -> Self {
|
|
let (ts, ms, fs) = if adapter.get_info().backend == wgpu::Backend::Vulkan {
|
|
(
|
|
compile_glsl(device, "task"),
|
|
compile_glsl(device, "mesh"),
|
|
compile_glsl(device, "frag"),
|
|
)
|
|
} else if adapter.get_info().backend == wgpu::Backend::Dx12 {
|
|
(
|
|
compile_hlsl(device, "Task", "as"),
|
|
compile_hlsl(device, "Mesh", "ms"),
|
|
compile_hlsl(device, "Frag", "ps"),
|
|
)
|
|
} else {
|
|
panic!("Example can only run on vulkan or dx12");
|
|
};
|
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: None,
|
|
bind_group_layouts: &[],
|
|
push_constant_ranges: &[],
|
|
});
|
|
let pipeline = device.create_mesh_pipeline(&wgpu::MeshPipelineDescriptor {
|
|
label: None,
|
|
layout: Some(&pipeline_layout),
|
|
task: Some(wgpu::TaskState {
|
|
module: &ts,
|
|
entry_point: Some("main"),
|
|
compilation_options: Default::default(),
|
|
}),
|
|
mesh: wgpu::MeshState {
|
|
module: &ms,
|
|
entry_point: Some("main"),
|
|
compilation_options: Default::default(),
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &fs,
|
|
entry_point: Some("main"),
|
|
compilation_options: Default::default(),
|
|
targets: &[Some(config.view_formats[0].into())],
|
|
}),
|
|
primitive: wgpu::PrimitiveState {
|
|
cull_mode: Some(wgpu::Face::Back),
|
|
..Default::default()
|
|
},
|
|
depth_stencil: None,
|
|
multisample: Default::default(),
|
|
multiview: None,
|
|
cache: None,
|
|
});
|
|
Self { pipeline }
|
|
}
|
|
fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
|
|
let mut encoder =
|
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
{
|
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
label: None,
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
view,
|
|
resolve_target: None,
|
|
ops: wgpu::Operations {
|
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
|
r: 0.1,
|
|
g: 0.2,
|
|
b: 0.3,
|
|
a: 1.0,
|
|
}),
|
|
store: wgpu::StoreOp::Store,
|
|
},
|
|
depth_slice: None,
|
|
})],
|
|
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);
|
|
rpass.pop_debug_group();
|
|
rpass.insert_debug_marker("Draw!");
|
|
rpass.draw_mesh_tasks(1, 1, 1);
|
|
}
|
|
queue.submit(Some(encoder.finish()));
|
|
}
|
|
fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
|
|
Default::default()
|
|
}
|
|
fn required_features() -> wgpu::Features {
|
|
wgpu::Features::EXPERIMENTAL_MESH_SHADER | wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS
|
|
}
|
|
fn required_limits() -> wgpu::Limits {
|
|
wgpu::Limits::defaults().using_recommended_minimum_mesh_shader_values()
|
|
}
|
|
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>("mesh_shader");
|
|
}
|