mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-01-10 06:58:12 -05:00
hlsl-out: Add support for push constants (#2005)
Push constants need to be configured by the consumer which must pass the bind target of the constant buffer used for the push constants.
This commit is contained in:
4
Makefile
4
Makefile
@@ -69,7 +69,7 @@ validate-wgsl: $(SNAPSHOTS_BASE_OUT)/wgsl/*.wgsl
|
||||
cargo run $${file}; \
|
||||
done
|
||||
|
||||
validate-hlsl-dxc: SHELL:=/bin/bash # required because config files uses arrays
|
||||
validate-hlsl-dxc: SHELL:=/usr/bin/env bash # required because config files uses arrays
|
||||
validate-hlsl-dxc: $(SNAPSHOTS_BASE_OUT)/hlsl/*.hlsl
|
||||
@set -e && for file in $^ ; do \
|
||||
DXC_PARAMS="-Wno-parentheses-equality -Zi -Qembed_debug -Od"; \
|
||||
@@ -94,7 +94,7 @@ validate-hlsl-dxc: $(SNAPSHOTS_BASE_OUT)/hlsl/*.hlsl
|
||||
echo "======================"; \
|
||||
done
|
||||
|
||||
validate-hlsl-fxc: SHELL:=/bin/bash # required because config files uses arrays
|
||||
validate-hlsl-fxc: SHELL:=/usr/bin/env bash # required because config files uses arrays
|
||||
validate-hlsl-fxc: $(SNAPSHOTS_BASE_OUT)/hlsl/*.hlsl
|
||||
@set -e && for file in $^ ; do \
|
||||
FXC_PARAMS="-Zi -Od"; \
|
||||
|
||||
@@ -189,6 +189,8 @@ pub struct Options {
|
||||
/// Add special constants to `SV_VertexIndex` and `SV_InstanceIndex`,
|
||||
/// to make them work like in Vulkan/Metal, with help of the host.
|
||||
pub special_constants_binding: Option<BindTarget>,
|
||||
/// Bind target of the push constant buffer
|
||||
pub push_constants_target: Option<BindTarget>,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
@@ -198,6 +200,7 @@ impl Default for Options {
|
||||
binding_map: BindingMap::default(),
|
||||
fake_missing_bindings: true,
|
||||
special_constants_binding: None,
|
||||
push_constants_target: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,12 +623,45 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
self.write_type(module, global.ty)?;
|
||||
register
|
||||
}
|
||||
crate::AddressSpace::PushConstant => unimplemented!("Push constants"),
|
||||
crate::AddressSpace::PushConstant => {
|
||||
// The type of the push constants will be wrapped in `ConstantBuffer`
|
||||
write!(self.out, "ConstantBuffer<")?;
|
||||
"b"
|
||||
}
|
||||
};
|
||||
|
||||
// If the global is a push constant write the type now because it will be a
|
||||
// generic argument to `ConstantBuffer`
|
||||
if global.space == crate::AddressSpace::PushConstant {
|
||||
self.write_global_type(module, global.ty)?;
|
||||
|
||||
// need to write the array size if the type was emitted with `write_type`
|
||||
if let TypeInner::Array { base, size, .. } = module.types[global.ty].inner {
|
||||
self.write_array_size(module, base, size)?;
|
||||
}
|
||||
|
||||
// Close the angled brackets for the generic argument
|
||||
write!(self.out, ">")?;
|
||||
}
|
||||
|
||||
let name = &self.names[&NameKey::GlobalVariable(handle)];
|
||||
write!(self.out, " {}", name)?;
|
||||
|
||||
// Push constants need to be assigned a binding explicitly by the consumer
|
||||
// since naga has no way to know the binding from the shader alone
|
||||
if global.space == crate::AddressSpace::PushConstant {
|
||||
let target = self
|
||||
.options
|
||||
.push_constants_target
|
||||
.as_ref()
|
||||
.expect("No bind target was defined for the push constants block");
|
||||
write!(self.out, ": register(b{}", target.register)?;
|
||||
if target.space != 0 {
|
||||
write!(self.out, ", space{}", target.space)?;
|
||||
}
|
||||
write!(self.out, ")")?;
|
||||
}
|
||||
|
||||
if let Some(ref binding) = global.binding {
|
||||
// this was already resolved earlier when we started evaluating an entry point.
|
||||
let bt = self.options.resolve_resource_binding(binding).unwrap();
|
||||
@@ -665,34 +698,13 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
if global.space == crate::AddressSpace::Uniform {
|
||||
write!(self.out, " {{ ")?;
|
||||
|
||||
let matrix_data = get_inner_matrix_data(module, global.ty);
|
||||
self.write_global_type(module, global.ty)?;
|
||||
|
||||
// We treat matrices of the form `matCx2` as a sequence of C `vec2`s.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if let Some(MatrixType {
|
||||
columns,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
}) = matrix_data
|
||||
{
|
||||
write!(
|
||||
self.out,
|
||||
"__mat{}x2 {}",
|
||||
columns as u8,
|
||||
&self.names[&NameKey::GlobalVariable(handle)]
|
||||
)?;
|
||||
} else {
|
||||
// Even though Naga IR matrices are column-major, we must describe
|
||||
// matrices passed from the CPU as being in row-major order.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if matrix_data.is_some() {
|
||||
write!(self.out, "row_major ")?;
|
||||
}
|
||||
|
||||
self.write_type(module, global.ty)?;
|
||||
let sub_name = &self.names[&NameKey::GlobalVariable(handle)];
|
||||
write!(self.out, " {}", sub_name)?;
|
||||
}
|
||||
write!(
|
||||
self.out,
|
||||
" {}",
|
||||
&self.names[&NameKey::GlobalVariable(handle)]
|
||||
)?;
|
||||
|
||||
// need to write the array size if the type was emitted with `write_type`
|
||||
if let TypeInner::Array { base, size, .. } = module.types[global.ty].inner {
|
||||
@@ -829,27 +841,7 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
TypeInner::Array { base, size, .. } => {
|
||||
// HLSL arrays are written as `type name[size]`
|
||||
|
||||
let matrix_data = get_inner_matrix_data(module, member.ty);
|
||||
|
||||
// We treat matrices of the form `matCx2` as a sequence of C `vec2`s.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if let Some(MatrixType {
|
||||
columns,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
}) = matrix_data
|
||||
{
|
||||
write!(self.out, "__mat{}x2", columns as u8)?;
|
||||
} else {
|
||||
// Even though Naga IR matrices are column-major, we must describe
|
||||
// matrices passed from the CPU as being in row-major order.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if matrix_data.is_some() {
|
||||
write!(self.out, "row_major ")?;
|
||||
}
|
||||
|
||||
self.write_type(module, base)?;
|
||||
}
|
||||
self.write_global_type(module, member.ty)?;
|
||||
|
||||
// Write `name`
|
||||
write!(
|
||||
@@ -923,6 +915,40 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper method used to write global/structs non image/sampler types
|
||||
///
|
||||
/// # Notes
|
||||
/// Adds no trailing or leading whitespace
|
||||
pub(super) fn write_global_type(
|
||||
&mut self,
|
||||
module: &Module,
|
||||
ty: Handle<crate::Type>,
|
||||
) -> BackendResult {
|
||||
let matrix_data = get_inner_matrix_data(module, ty);
|
||||
|
||||
// We treat matrices of the form `matCx2` as a sequence of C `vec2`s.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if let Some(MatrixType {
|
||||
columns,
|
||||
rows: crate::VectorSize::Bi,
|
||||
width: 4,
|
||||
}) = matrix_data
|
||||
{
|
||||
write!(self.out, "__mat{}x2", columns as u8)?;
|
||||
} else {
|
||||
// Even though Naga IR matrices are column-major, we must describe
|
||||
// matrices passed from the CPU as being in row-major order.
|
||||
// See the module-level block comment in mod.rs for details.
|
||||
if matrix_data.is_some() {
|
||||
write!(self.out, "row_major ")?;
|
||||
}
|
||||
|
||||
self.write_type(module, ty)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper method used to write non image/sampler types
|
||||
///
|
||||
/// # Notes
|
||||
|
||||
@@ -8,4 +8,11 @@
|
||||
writer_flags: (bits: 0),
|
||||
binding_map: {},
|
||||
),
|
||||
hlsl: (
|
||||
shader_model: V5_1,
|
||||
binding_map: {},
|
||||
fake_missing_bindings: true,
|
||||
special_constants_binding: Some((space: 1, register: 0)),
|
||||
push_constants_target: Some((space: 0, register: 0)),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -7,6 +7,14 @@ struct FragmentIn {
|
||||
@location(0) color: vec4<f32>
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vert_main(
|
||||
@location(0) pos : vec2<f32>,
|
||||
@builtin(vertex_index) vi: u32,
|
||||
) -> @builtin(position) vec4<f32> {
|
||||
return vec4<f32>(f32(vi) * pc.multiplier * pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn main(in: FragmentIn) -> @location(0) vec4<f32> {
|
||||
return in.color * pc.multiplier;
|
||||
|
||||
23
tests/out/glsl/push-constants.vert_main.Vertex.glsl
Normal file
23
tests/out/glsl/push-constants.vert_main.Vertex.glsl
Normal file
@@ -0,0 +1,23 @@
|
||||
#version 320 es
|
||||
|
||||
precision highp float;
|
||||
precision highp int;
|
||||
|
||||
struct PushConstants {
|
||||
float multiplier;
|
||||
};
|
||||
struct FragmentIn {
|
||||
vec4 color;
|
||||
};
|
||||
uniform PushConstants pc;
|
||||
|
||||
layout(location = 0) in vec2 _p2vs_location0;
|
||||
|
||||
void main() {
|
||||
vec2 pos = _p2vs_location0;
|
||||
uint vi = uint(gl_VertexID);
|
||||
float _e5 = pc.multiplier;
|
||||
gl_Position = vec4(((float(vi) * _e5) * pos), 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
33
tests/out/hlsl/push-constants.hlsl
Normal file
33
tests/out/hlsl/push-constants.hlsl
Normal file
@@ -0,0 +1,33 @@
|
||||
struct NagaConstants {
|
||||
int base_vertex;
|
||||
int base_instance;
|
||||
uint other;
|
||||
};
|
||||
ConstantBuffer<NagaConstants> _NagaConstants: register(b0, space1);
|
||||
|
||||
struct PushConstants {
|
||||
float multiplier;
|
||||
};
|
||||
|
||||
struct FragmentIn {
|
||||
float4 color : LOC0;
|
||||
};
|
||||
|
||||
ConstantBuffer<PushConstants> pc: register(b0);
|
||||
|
||||
struct FragmentInput_main {
|
||||
float4 color : LOC0;
|
||||
};
|
||||
|
||||
float4 vert_main(float2 pos : LOC0, uint vi : SV_VertexID) : SV_Position
|
||||
{
|
||||
float _expr5 = pc.multiplier;
|
||||
return float4(((float((_NagaConstants.base_vertex + vi)) * _expr5) * pos), 0.0, 1.0);
|
||||
}
|
||||
|
||||
float4 main(FragmentInput_main fragmentinput_main) : SV_Target0
|
||||
{
|
||||
FragmentIn in_ = { fragmentinput_main.color };
|
||||
float _expr4 = pc.multiplier;
|
||||
return (in_.color * _expr4);
|
||||
}
|
||||
3
tests/out/hlsl/push-constants.hlsl.config
Normal file
3
tests/out/hlsl/push-constants.hlsl.config
Normal file
@@ -0,0 +1,3 @@
|
||||
vertex=(vert_main:vs_5_1 )
|
||||
fragment=(main:ps_5_1 )
|
||||
compute=()
|
||||
@@ -471,7 +471,7 @@ fn convert_wgsl() {
|
||||
Targets::SPIRV | Targets::METAL | Targets::HLSL | Targets::WGSL | Targets::GLSL,
|
||||
),
|
||||
("extra", Targets::SPIRV | Targets::METAL | Targets::WGSL),
|
||||
("push-constants", Targets::GLSL),
|
||||
("push-constants", Targets::GLSL | Targets::HLSL),
|
||||
(
|
||||
"operators",
|
||||
Targets::SPIRV | Targets::METAL | Targets::GLSL | Targets::HLSL | Targets::WGSL,
|
||||
|
||||
Reference in New Issue
Block a user