Skip to content

Initial precompiled shaders implementation #7834

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 42 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
21e3bfd
Unsure but these were prior changes
SupaMaggie70Incorporated Jun 19, 2025
d9e089d
Merge branch 'dxil-passthrough' of https://github.com/supamaggie70inc…
SupaMaggie70Incorporated Jun 19, 2025
818b1fe
Fixed feature thing
SupaMaggie70Incorporated Jun 19, 2025
873a0ee
Mostly finished dxil passthrough
SupaMaggie70Incorporated Jun 19, 2025
da84fed
Attempted to add HLSL passthrough
SupaMaggie70Incorporated Jun 19, 2025
5680c9e
Tried to fix compiles
SupaMaggie70Incorporated Jun 19, 2025
05b8cda
Tried to fix more clippy lints
SupaMaggie70Incorporated Jun 19, 2025
4c28f2a
Added initial feature, going back to fix issues with DXIL rn
SupaMaggie70Incorporated Jun 20, 2025
d050a20
Tried to fix some potential issues
SupaMaggie70Incorporated Jun 20, 2025
5c1c8c8
Merge branch 'dxil-passthrough' into precompiled-shaders
SupaMaggie70Incorporated Jun 20, 2025
3ca8ce4
Initial work
SupaMaggie70Incorporated Jun 20, 2025
f7ffe36
Tried to fix metal compiles
SupaMaggie70Incorporated Jun 20, 2025
5006d54
Fixed warning
SupaMaggie70Incorporated Jun 20, 2025
d69e277
Added my ideas for changes
SupaMaggie70Incorporated Jun 20, 2025
3f9b7b8
Tried to expose precompiled shaders to metal
SupaMaggie70Incorporated Jun 20, 2025
0f17512
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jun 25, 2025
34d076a
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jun 27, 2025
6d49154
How do these things even happen?
SupaMaggie70Incorporated Jun 27, 2025
4b19ca3
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 1, 2025
e7cc939
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 3, 2025
18dffd5
More work, adapted with some of Cw's advice
SupaMaggie70Incorporated Jul 5, 2025
1eb4492
Tried to fix some compile errors. Now build!!!
SupaMaggie70Incorporated Jul 5, 2025
8f1b59c
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 5, 2025
c4a3160
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 9, 2025
fc7152f
Small change
SupaMaggie70Incorporated Jul 9, 2025
1a1dfe5
Update wgpu-types/src/features.rs
SupaMaggie70Incorporated Jul 9, 2025
fa16188
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 9, 2025
4c8aa72
Deleted the precompiled shader spec
SupaMaggie70Incorporated Jul 9, 2025
4e97df8
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 9, 2025
672738a
Pushing now to get hal errors on other backends
SupaMaggie70Incorporated Jul 9, 2025
dfbeacc
Made some slight fixes, CI will now report more hal errors
SupaMaggie70Incorporated Jul 9, 2025
5d0ed0b
Tried to write passthrough for webgpu backend
SupaMaggie70Incorporated Jul 9, 2025
66c6000
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 9, 2025
98fcff9
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 9, 2025
b105dc0
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 10, 2025
ca381ca
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 10, 2025
681857e
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 11, 2025
b542ba5
Various changes as requested from review
SupaMaggie70Incorporated Jul 11, 2025
ff61dde
Fixed issues with trace
SupaMaggie70Incorporated Jul 11, 2025
1e454b2
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 11, 2025
3ae8b38
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 11, 2025
7f4e64f
Merge branch 'trunk' into precompiled-shaders
SupaMaggie70Incorporated Jul 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ We have merged the acceleration structure feature into the `RayQuery` feature. T

By @Vecvec in [#7913](https://github.com/gfx-rs/wgpu/pull/7913).

### General
- Added `Features::EXPERIMENTAL_PRECOMPILED_SHADERS`, replacing existing passthrough types with a unified `CreateShaderModuleDescriptorPassthrough` which allows passing multiple shader codes for different backends. By @SupaMaggie70Incorporated in [#7834](https://github.com/gfx-rs/wgpu/pull/7834)

## v26.0.1 (2025-07-10)

### Bug Fixes
Expand Down
9 changes: 0 additions & 9 deletions deno_webgpu/webidl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,6 @@ pub enum GPUFeatureName {
VertexWritableStorage,
#[webidl(rename = "clear-texture")]
ClearTexture,
#[webidl(rename = "msl-shader-passthrough")]
MslShaderPassthrough,
#[webidl(rename = "spirv-shader-passthrough")]
SpirvShaderPassthrough,
#[webidl(rename = "multiview")]
Multiview,
#[webidl(rename = "vertex-attribute-64-bit")]
Expand Down Expand Up @@ -482,8 +478,6 @@ pub fn feature_names_to_features(names: Vec<GPUFeatureName>) -> wgpu_types::Feat
GPUFeatureName::ConservativeRasterization => Features::CONSERVATIVE_RASTERIZATION,
GPUFeatureName::VertexWritableStorage => Features::VERTEX_WRITABLE_STORAGE,
GPUFeatureName::ClearTexture => Features::CLEAR_TEXTURE,
GPUFeatureName::MslShaderPassthrough => Features::MSL_SHADER_PASSTHROUGH,
GPUFeatureName::SpirvShaderPassthrough => Features::SPIRV_SHADER_PASSTHROUGH,
GPUFeatureName::Multiview => Features::MULTIVIEW,
GPUFeatureName::VertexAttribute64Bit => Features::VERTEX_ATTRIBUTE_64BIT,
GPUFeatureName::ShaderF64 => Features::SHADER_F64,
Expand Down Expand Up @@ -626,9 +620,6 @@ pub fn features_to_feature_names(features: wgpu_types::Features) -> HashSet<GPUF
if features.contains(wgpu_types::Features::CLEAR_TEXTURE) {
return_features.insert(ClearTexture);
}
if features.contains(wgpu_types::Features::SPIRV_SHADER_PASSTHROUGH) {
return_features.insert(SpirvShaderPassthrough);
}
if features.contains(wgpu_types::Features::MULTIVIEW) {
return_features.insert(Multiview);
}
Expand Down
90 changes: 89 additions & 1 deletion player/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern crate wgpu_types as wgt;

use wgc::device::trace;

use std::{borrow::Cow, fs, path::Path};
use std::{borrow::Cow, fs, io::Read, path::Path};

pub trait GlobalPlay {
fn encode_commands(
Expand Down Expand Up @@ -295,6 +295,94 @@ impl GlobalPlay for wgc::global::Global {
println!("shader compilation error:\n---{code}\n---\n{e}");
}
}
Action::CreateShaderModulePassthrough {
id,
data,
entry_point,
label,
num_workgroups,
reflection,
runtime_checks,
} => {
let spirv = data.iter().find_map(|a| {
if a.ends_with(".spv") {
let mut file = fs::File::open(dir.join(a)).unwrap();
let word_count = file.metadata().unwrap().len() as usize / 4;
let mut vec = Vec::<u32>::with_capacity(word_count);
unsafe {
file.read_exact(std::slice::from_raw_parts_mut(
vec.as_mut_ptr() as *mut u8,
vec.len() * 4,
))
.unwrap();
vec.set_len(word_count);
}
Some(Cow::Owned(vec))
} else {
None
}
});
let dxil = data.iter().find_map(|a| {
if a.ends_with(".dxil") {
let vec = std::fs::read(dir.join(a)).unwrap();
Some(Cow::Owned(vec))
} else {
None
}
});
let hlsl = data.iter().find_map(|a| {
if a.ends_with(".hlsl") {
let code = fs::read_to_string(dir.join(a)).unwrap();
Some(Cow::Owned(code))
} else {
None
}
});
let msl = data.iter().find_map(|a| {
if a.ends_with(".msl") {
let code = fs::read_to_string(dir.join(a)).unwrap();
Some(Cow::Owned(code))
} else {
None
}
});
let glsl = data.iter().find_map(|a| {
if a.ends_with(".glsl") {
let code = fs::read_to_string(dir.join(a)).unwrap();
Some(Cow::Owned(code))
} else {
None
}
});
let wgsl = data.iter().find_map(|a| {
if a.ends_with(".wgsl") {
let code = fs::read_to_string(dir.join(a)).unwrap();
Some(Cow::Owned(code))
} else {
None
}
});
let desc = wgt::CreateShaderModuleDescriptorPassthrough {
entry_point,
label,
num_workgroups,
reflection,
runtime_checks,

spirv,
dxil,
hlsl,
msl,
glsl,
wgsl,
};
let (_, error) = unsafe {
self.device_create_shader_module_passthrough(device, &desc, Some(id))
};
if let Some(e) = error {
println!("shader compilation error: {e}");
}
}
Action::DestroyShaderModule(id) => {
self.shader_module_drop(id);
}
Expand Down
52 changes: 22 additions & 30 deletions wgpu-core/src/device/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,36 +979,28 @@ impl Global {

#[cfg(feature = "trace")]
if let Some(ref mut trace) = *device.trace.lock() {
let data = trace.make_binary(desc.trace_binary_ext(), desc.trace_data());
trace.add(trace::Action::CreateShaderModule {
let mut file_names = Vec::new();
for (data, ext) in [
(desc.spirv.as_ref().map(|a| bytemuck::cast_slice(a)), "spv"),
(desc.dxil.as_deref(), "dxil"),
(desc.hlsl.as_ref().map(|a| a.as_bytes()), "hlsl"),
(desc.msl.as_ref().map(|a| a.as_bytes()), "msl"),
(desc.glsl.as_ref().map(|a| a.as_bytes()), "glsl"),
(desc.wgsl.as_ref().map(|a| a.as_bytes()), "wgsl"),
] {
if let Some(data) = data {
file_names.push(trace.make_binary(ext, data));
}
}
trace.add(trace::Action::CreateShaderModulePassthrough {
id: fid.id(),
desc: match desc {
pipeline::ShaderModuleDescriptorPassthrough::SpirV(inner) => {
pipeline::ShaderModuleDescriptor {
label: inner.label.clone(),
runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
}
}
pipeline::ShaderModuleDescriptorPassthrough::Msl(inner) => {
pipeline::ShaderModuleDescriptor {
label: inner.label.clone(),
runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
}
}
pipeline::ShaderModuleDescriptorPassthrough::Dxil(inner) => {
pipeline::ShaderModuleDescriptor {
label: inner.label.clone(),
runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
}
}
pipeline::ShaderModuleDescriptorPassthrough::Hlsl(inner) => {
pipeline::ShaderModuleDescriptor {
label: inner.label.clone(),
runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
}
}
},
data,
data: file_names,

entry_point: desc.entry_point.clone(),
label: desc.label.clone(),
num_workgroups: desc.num_workgroups,
reflection: desc.reflection.clone(),
runtime_checks: desc.runtime_checks,
});
};

Expand All @@ -1023,7 +1015,7 @@ impl Global {
return (id, None);
};

let id = fid.assign(Fallible::Invalid(Arc::new(desc.label().to_string())));
let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
(id, Some(error))
}

Expand Down
75 changes: 47 additions & 28 deletions wgpu-core/src/device/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1797,39 +1797,58 @@ impl Device {
descriptor: &pipeline::ShaderModuleDescriptorPassthrough<'a>,
) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> {
self.check_is_valid()?;
let hal_shader = match descriptor {
pipeline::ShaderModuleDescriptorPassthrough::SpirV(inner) => {
self.require_features(wgt::Features::SPIRV_SHADER_PASSTHROUGH)?;
hal::ShaderInput::SpirV(&inner.source)
}
pipeline::ShaderModuleDescriptorPassthrough::Msl(inner) => {
self.require_features(wgt::Features::MSL_SHADER_PASSTHROUGH)?;
hal::ShaderInput::Msl {
shader: inner.source.to_string(),
entry_point: inner.entry_point.to_string(),
num_workgroups: inner.num_workgroups,
}
}
pipeline::ShaderModuleDescriptorPassthrough::Dxil(inner) => {
self.require_features(wgt::Features::HLSL_DXIL_SHADER_PASSTHROUGH)?;
hal::ShaderInput::Dxil {
shader: inner.source,
entry_point: inner.entry_point.clone(),
num_workgroups: inner.num_workgroups,
self.require_features(wgt::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS)?;

// TODO: when we get to use if-let chains, this will be a little nicer!

let hal_shader = match self.adapter.backend() {
wgt::Backend::Vulkan => hal::ShaderInput::SpirV(
descriptor
.spirv
.as_ref()
.ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
),
wgt::Backend::Dx12 => {
if let Some(dxil) = &descriptor.dxil {
hal::ShaderInput::Dxil {
shader: dxil,
entry_point: descriptor.entry_point.clone(),
num_workgroups: descriptor.num_workgroups,
}
} else if let Some(hlsl) = &descriptor.hlsl {
hal::ShaderInput::Hlsl {
shader: hlsl,
entry_point: descriptor.entry_point.clone(),
num_workgroups: descriptor.num_workgroups,
}
} else {
return Err(pipeline::CreateShaderModuleError::NotCompiledForBackend);
}
}
pipeline::ShaderModuleDescriptorPassthrough::Hlsl(inner) => {
self.require_features(wgt::Features::HLSL_DXIL_SHADER_PASSTHROUGH)?;
hal::ShaderInput::Hlsl {
shader: inner.source,
entry_point: inner.entry_point.clone(),
num_workgroups: inner.num_workgroups,
}
wgt::Backend::Metal => hal::ShaderInput::Msl {
shader: descriptor
.msl
.as_ref()
.ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
entry_point: descriptor.entry_point.clone(),
num_workgroups: descriptor.num_workgroups,
},
wgt::Backend::Gl => hal::ShaderInput::Glsl {
shader: descriptor
.glsl
.as_ref()
.ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
entry_point: descriptor.entry_point.clone(),
num_workgroups: descriptor.num_workgroups,
},
wgt::Backend::Noop => {
return Err(pipeline::CreateShaderModuleError::NotCompiledForBackend)
}
wgt::Backend::BrowserWebGpu => unreachable!(),
};

let hal_desc = hal::ShaderModuleDescriptor {
label: descriptor.label().to_hal(self.instance_flags),
label: descriptor.label.to_hal(self.instance_flags),
runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
};

Expand All @@ -1852,7 +1871,7 @@ impl Device {
raw: ManuallyDrop::new(raw),
device: self.clone(),
interface: None,
label: descriptor.label().to_string(),
label: descriptor.label.to_string(),
};

Ok(Arc::new(module))
Expand Down
10 changes: 10 additions & 0 deletions wgpu-core/src/device/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ pub enum Action<'a> {
desc: crate::pipeline::ShaderModuleDescriptor<'a>,
data: FileName,
},
CreateShaderModulePassthrough {
id: id::ShaderModuleId,
data: Vec<FileName>,

entry_point: String,
label: crate::Label<'a>,
num_workgroups: (u32, u32, u32),
reflection: Option<wgt::ShaderModuleReflection>,
runtime_checks: wgt::ShaderRuntimeChecks,
},
DestroyShaderModule(id::ShaderModuleId),
CreateComputePipeline {
id: id::ComputePipelineId,
Expand Down
3 changes: 3 additions & 0 deletions wgpu-core/src/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ pub enum CreateShaderModuleError {
group: u32,
limit: u32,
},
#[error("Generic shader passthrough does not contain any code compatible with this backend.")]
NotCompiledForBackend,
}

impl WebGpuError for CreateShaderModuleError {
Expand All @@ -147,6 +149,7 @@ impl WebGpuError for CreateShaderModuleError {
Self::ParsingGlsl(..) => return ErrorType::Validation,
#[cfg(feature = "spirv")]
Self::ParsingSpirV(..) => return ErrorType::Validation,
Self::NotCompiledForBackend => return ErrorType::Validation,
};
e.webgpu_error_type()
}
Expand Down
3 changes: 2 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ impl super::Adapter {
| wgt::Features::DUAL_SOURCE_BLENDING
| wgt::Features::TEXTURE_FORMAT_NV12
| wgt::Features::FLOAT32_FILTERABLE
| wgt::Features::TEXTURE_ATOMIC;
| wgt::Features::TEXTURE_ATOMIC
| wgt::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS;

//TODO: in order to expose this, we need to run a compute shader
// that extract the necessary statistics out of the D3D12 result.
Expand Down
11 changes: 5 additions & 6 deletions wgpu-hal/src/dx12/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1700,12 +1700,6 @@ impl crate::Device for super::Device {
raw_name,
runtime_checks: desc.runtime_checks,
}),
crate::ShaderInput::SpirV(_) => {
panic!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend")
}
crate::ShaderInput::Msl { .. } => {
panic!("MSL_SHADER_PASSTHROUGH is not enabled for this backend")
}
crate::ShaderInput::Dxil {
shader,
entry_point,
Expand All @@ -1732,6 +1726,11 @@ impl crate::Device for super::Device {
raw_name,
runtime_checks: desc.runtime_checks,
}),
crate::ShaderInput::SpirV(_)
| crate::ShaderInput::Msl { .. }
| crate::ShaderInput::Glsl { .. } => {
unreachable!()
}
}
}
unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) {
Expand Down
Loading