mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
spv-out: Support arrayLength of a dynamically indexed bindings array
This commit is contained in:
parent
bfe0b90740
commit
3a467ad93d
@ -48,25 +48,39 @@ impl<'w> BlockContext<'w> {
|
|||||||
// inside a buffer that is itself an element in a buffer bindings array.
|
// inside a buffer that is itself an element in a buffer bindings array.
|
||||||
// SPIR-V requires that runtime-sized arrays are wrapped in structs.
|
// SPIR-V requires that runtime-sized arrays are wrapped in structs.
|
||||||
// See `helpers::global_needs_wrapper` and its uses.
|
// See `helpers::global_needs_wrapper` and its uses.
|
||||||
let (opt_array_index, global_handle, opt_last_member_index) = match self
|
let (opt_array_index_id, global_handle, opt_last_member_index) = match self
|
||||||
.ir_function
|
.ir_function
|
||||||
.expressions[array]
|
.expressions[array]
|
||||||
{
|
{
|
||||||
// Note that SPIR-V forbids `OpArrayLength` on a variable pointer,
|
|
||||||
// so we aren't handling `crate::Expression::Access` here.
|
|
||||||
crate::Expression::AccessIndex { base, index } => {
|
crate::Expression::AccessIndex { base, index } => {
|
||||||
match self.ir_function.expressions[base] {
|
match self.ir_function.expressions[base] {
|
||||||
// The global variable is an array of buffer bindings of structs,
|
// The global variable is an array of buffer bindings of structs,
|
||||||
// and we are accessing the last member.
|
// we are accessing one of them with a static index,
|
||||||
|
// and the last member of it.
|
||||||
crate::Expression::AccessIndex {
|
crate::Expression::AccessIndex {
|
||||||
base: base_outer,
|
base: base_outer,
|
||||||
index: index_outer,
|
index: index_outer,
|
||||||
} => match self.ir_function.expressions[base_outer] {
|
} => match self.ir_function.expressions[base_outer] {
|
||||||
crate::Expression::GlobalVariable(handle) => {
|
crate::Expression::GlobalVariable(handle) => {
|
||||||
(Some(index_outer), handle, Some(index))
|
let index_id = self.get_index_constant(index_outer);
|
||||||
|
(Some(index_id), handle, Some(index))
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Validation("array length expression case-1a")),
|
_ => return Err(Error::Validation("array length expression case-1a")),
|
||||||
},
|
},
|
||||||
|
// The global variable is an array of buffer bindings of structs,
|
||||||
|
// we are accessing one of them with a dynamic index,
|
||||||
|
// and the last member of it.
|
||||||
|
crate::Expression::Access {
|
||||||
|
base: base_outer,
|
||||||
|
index: index_outer,
|
||||||
|
} => match self.ir_function.expressions[base_outer] {
|
||||||
|
crate::Expression::GlobalVariable(handle) => {
|
||||||
|
let index_id = self.cached[index_outer];
|
||||||
|
(Some(index_id), handle, Some(index))
|
||||||
|
}
|
||||||
|
_ => return Err(Error::Validation("array length expression case-1b")),
|
||||||
|
},
|
||||||
|
// The global variable is a buffer, and we are accessing the last member.
|
||||||
crate::Expression::GlobalVariable(handle) => {
|
crate::Expression::GlobalVariable(handle) => {
|
||||||
let global = &self.ir_module.global_variables[handle];
|
let global = &self.ir_module.global_variables[handle];
|
||||||
match self.ir_module.types[global.ty].inner {
|
match self.ir_module.types[global.ty].inner {
|
||||||
@ -79,15 +93,27 @@ impl<'w> BlockContext<'w> {
|
|||||||
_ => return Err(Error::Validation("array length expression case-1c")),
|
_ => return Err(Error::Validation("array length expression case-1c")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// The global variable is an array of buffer bindings of arrays.
|
||||||
|
crate::Expression::Access { base, index } => match self.ir_function.expressions[base] {
|
||||||
|
crate::Expression::GlobalVariable(handle) => {
|
||||||
|
let index_id = self.cached[index];
|
||||||
|
let global = &self.ir_module.global_variables[handle];
|
||||||
|
match self.ir_module.types[global.ty].inner {
|
||||||
|
crate::TypeInner::BindingArray { .. } => (Some(index_id), handle, None),
|
||||||
|
_ => return Err(Error::Validation("array length expression case-2a")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(Error::Validation("array length expression case-2b")),
|
||||||
|
},
|
||||||
// The global variable is a run-time array.
|
// The global variable is a run-time array.
|
||||||
crate::Expression::GlobalVariable(handle) => {
|
crate::Expression::GlobalVariable(handle) => {
|
||||||
let global = &self.ir_module.global_variables[handle];
|
let global = &self.ir_module.global_variables[handle];
|
||||||
if !global_needs_wrapper(self.ir_module, global) {
|
if !global_needs_wrapper(self.ir_module, global) {
|
||||||
return Err(Error::Validation("array length expression case-2"));
|
return Err(Error::Validation("array length expression case-3"));
|
||||||
}
|
}
|
||||||
(None, handle, None)
|
(None, handle, None)
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Validation("array length expression case-3")),
|
_ => return Err(Error::Validation("array length expression case-4")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let gvar = self.writer.global_variables[global_handle.index()].clone();
|
let gvar = self.writer.global_variables[global_handle.index()].clone();
|
||||||
@ -103,17 +129,16 @@ impl<'w> BlockContext<'w> {
|
|||||||
(0, gvar.var_id)
|
(0, gvar.var_id)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let structure_id = match opt_array_index {
|
let structure_id = match opt_array_index_id {
|
||||||
// We are indexing inside a binding array, generate the access op.
|
// We are indexing inside a binding array, generate the access op.
|
||||||
Some(index) => {
|
Some(index_id) => {
|
||||||
let element_type_id = match self.ir_module.types[global.ty].inner {
|
let element_type_id = match self.ir_module.types[global.ty].inner {
|
||||||
crate::TypeInner::BindingArray { base, size: _ } => {
|
crate::TypeInner::BindingArray { base, size: _ } => {
|
||||||
let class = map_storage_class(global.space);
|
let class = map_storage_class(global.space);
|
||||||
self.get_pointer_id(base, class)?
|
self.get_pointer_id(base, class)?
|
||||||
}
|
}
|
||||||
_ => return Err(Error::Validation("array length expression case-4")),
|
_ => return Err(Error::Validation("array length expression case-5")),
|
||||||
};
|
};
|
||||||
let index_id = self.get_index_constant(index);
|
|
||||||
let structure_id = self.gen_id();
|
let structure_id = self.gen_id();
|
||||||
block.body.push(Instruction::access_chain(
|
block.body.push(Instruction::access_chain(
|
||||||
element_type_id,
|
element_type_id,
|
||||||
|
|||||||
@ -510,7 +510,6 @@ impl super::Validator {
|
|||||||
ti.uniform_layout = Ok(Alignment::MIN_UNIFORM);
|
ti.uniform_layout = Ok(Alignment::MIN_UNIFORM);
|
||||||
|
|
||||||
let mut min_offset = 0;
|
let mut min_offset = 0;
|
||||||
|
|
||||||
let mut prev_struct_data: Option<(u32, u32)> = None;
|
let mut prev_struct_data: Option<(u32, u32)> = None;
|
||||||
|
|
||||||
for (i, member) in members.iter().enumerate() {
|
for (i, member) in members.iter().enumerate() {
|
||||||
@ -662,6 +661,7 @@ impl super::Validator {
|
|||||||
// Currently Naga only supports binding arrays of structs for non-handle types.
|
// Currently Naga only supports binding arrays of structs for non-handle types.
|
||||||
match gctx.types[base].inner {
|
match gctx.types[base].inner {
|
||||||
crate::TypeInner::Struct { .. } => {}
|
crate::TypeInner::Struct { .. } => {}
|
||||||
|
crate::TypeInner::Array { .. } => {}
|
||||||
_ => return Err(TypeError::BindingArrayBaseTypeNotStruct(base)),
|
_ => return Err(TypeError::BindingArrayBaseTypeNotStruct(base)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,8 @@ fn main(fragment_in: FragmentIn) -> @location(0) u32 {
|
|||||||
u1 += storage_array[non_uniform_index].x;
|
u1 += storage_array[non_uniform_index].x;
|
||||||
|
|
||||||
u1 += arrayLength(&storage_array[0].far);
|
u1 += arrayLength(&storage_array[0].far);
|
||||||
|
u1 += arrayLength(&storage_array[uniform_index].far);
|
||||||
|
u1 += arrayLength(&storage_array[non_uniform_index].far);
|
||||||
|
|
||||||
return u1;
|
return u1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
; SPIR-V
|
; SPIR-V
|
||||||
; Version: 1.1
|
; Version: 1.1
|
||||||
; Generator: rspirv
|
; Generator: rspirv
|
||||||
; Bound: 68
|
; Bound: 76
|
||||||
OpCapability Shader
|
OpCapability Shader
|
||||||
OpCapability ShaderNonUniform
|
OpCapability ShaderNonUniform
|
||||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||||
@ -104,7 +104,17 @@ OpStore %31 %61
|
|||||||
%65 = OpLoad %3 %31
|
%65 = OpLoad %3 %31
|
||||||
%66 = OpIAdd %3 %65 %64
|
%66 = OpIAdd %3 %65 %64
|
||||||
OpStore %31 %66
|
OpStore %31 %66
|
||||||
%67 = OpLoad %3 %31
|
%67 = OpAccessChain %38 %11 %36
|
||||||
OpStore %23 %67
|
%68 = OpArrayLength %3 %67 1
|
||||||
|
%69 = OpLoad %3 %31
|
||||||
|
%70 = OpIAdd %3 %69 %68
|
||||||
|
OpStore %31 %70
|
||||||
|
%71 = OpAccessChain %38 %11 %37
|
||||||
|
%72 = OpArrayLength %3 %71 1
|
||||||
|
%73 = OpLoad %3 %31
|
||||||
|
%74 = OpIAdd %3 %73 %72
|
||||||
|
OpStore %31 %74
|
||||||
|
%75 = OpLoad %3 %31
|
||||||
|
OpStore %23 %75
|
||||||
OpReturn
|
OpReturn
|
||||||
OpFunctionEnd
|
OpFunctionEnd
|
||||||
@ -33,6 +33,10 @@ fn main(fragment_in: FragmentIn) -> @location(0) @interpolate(flat) u32 {
|
|||||||
u1_ = (_e23 + _e22);
|
u1_ = (_e23 + _e22);
|
||||||
let _e29 = u1_;
|
let _e29 = u1_;
|
||||||
u1_ = (_e29 + arrayLength((&storage_array[0].far)));
|
u1_ = (_e29 + arrayLength((&storage_array[0].far)));
|
||||||
let _e31 = u1_;
|
let _e35 = u1_;
|
||||||
return _e31;
|
u1_ = (_e35 + arrayLength((&storage_array[uniform_index].far)));
|
||||||
|
let _e41 = u1_;
|
||||||
|
u1_ = (_e41 + arrayLength((&storage_array[non_uniform_index].far)));
|
||||||
|
let _e43 = u1_;
|
||||||
|
return _e43;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user