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:
João Capucho
2022-08-29 11:58:02 +01:00
committed by GitHub
parent e7ddd3564c
commit 9df243c42c
9 changed files with 155 additions and 52 deletions

View File

@@ -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"; \

View File

@@ -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,
}
}
}

View File

@@ -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

View File

@@ -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)),
),
)

View File

@@ -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;

View 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;
}

View 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);
}

View File

@@ -0,0 +1,3 @@
vertex=(vert_main:vs_5_1 )
fragment=(main:ps_5_1 )
compute=()

View File

@@ -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,