diff --git a/naga/src/back/spv/image.rs b/naga/src/back/spv/image.rs index c185806cd..b412ac558 100644 --- a/naga/src/back/spv/image.rs +++ b/naga/src/back/spv/image.rs @@ -32,6 +32,9 @@ struct ImageCoordinates { /// The number of components in `value`, if it is a vector, or `None` if it /// is a scalar. size: Option, + + /// The type of each component of `value`. + scalar: crate::Scalar, } /// A trait for image access (load or store) code generators. @@ -274,15 +277,16 @@ impl BlockContext<'_> { None => { let value_id = coordinates_id; let type_id = self.get_expression_type_id(ty); - let size = match *inner_ty { - Ti::Scalar { .. } => None, - Ti::Vector { size, .. } => Some(size), + let (size, scalar) = match *inner_ty { + Ti::Scalar(scalar) => (None, scalar), + Ti::Vector { size, scalar } => (Some(size), scalar), _ => return Err(Error::Validation("coordinate type")), }; return Ok(ImageCoordinates { value_id, type_id, size, + scalar, }); } Some(ix) => ix, @@ -369,6 +373,7 @@ impl BlockContext<'_> { value_id, type_id, size: Some(size), + scalar: component_scalar, }) } @@ -401,7 +406,12 @@ impl BlockContext<'_> { /// If `coordinates` is a scalar, return a scalar one. Otherwise, return /// a vector of ones. fn write_coordinate_one(&mut self, coordinates: &ImageCoordinates) -> Result { - let one = self.get_scope_constant(1); + let one = self + .writer + .get_constant_scalar(match coordinates.scalar.kind { + crate::ScalarKind::Uint => crate::Literal::U32(1), + _ => crate::Literal::I32(1), + }); match coordinates.size { None => Ok(one), Some(vector_size) => { diff --git a/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.toml b/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.toml new file mode 100644 index 000000000..e29745c32 --- /dev/null +++ b/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.toml @@ -0,0 +1,8 @@ +targets = "SPIRV" + +[bounds_check_policies] +image_load = "Restrict" + +[spv] +debug = true +version = [1, 1] diff --git a/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.wgsl b/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.wgsl new file mode 100644 index 000000000..641e381d6 --- /dev/null +++ b/naga/tests/in/wgsl/bounds-check-image-restrict-unsigned.wgsl @@ -0,0 +1,36 @@ +@group(0) @binding(0) +var image_1d: texture_1d; + +fn test_textureLoad_1d(coords: u32, level: u32) -> vec4 { + return textureLoad(image_1d, coords, level); +} + +@group(0) @binding(1) +var image_2d: texture_2d; + +fn test_textureLoad_2d(coords: vec2, level: u32) -> vec4 { + return textureLoad(image_2d, coords, level); +} + +@group(0) @binding(2) +var image_2d_array: texture_2d_array; + +fn test_textureLoad_2d_array(coords: vec2, index: i32, level: u32) -> vec4 { + return textureLoad(image_2d_array, coords, index, level); +} + +@group(0) @binding(3) +var image_depth_2d: texture_depth_2d; + +fn test_textureLoad_depth_2d(coords: vec2, level: u32) -> f32 { + return textureLoad(image_depth_2d, coords, level); +} + +@fragment +fn fragment_shader() -> @location(0) vec4 { + test_textureLoad_1d(0u, 0u); + test_textureLoad_2d(vec2(), 0u); + test_textureLoad_2d_array(vec2(), 0, 0u); + test_textureLoad_depth_2d(vec2(), 0u); + return vec4(0.,0.,0.,0.); +} diff --git a/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm b/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm new file mode 100644 index 000000000..099d4a747 --- /dev/null +++ b/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm @@ -0,0 +1,204 @@ +; SPIR-V +; Version: 1.1 +; Generator: rspirv +; Bound: 106 +OpCapability Shader +OpCapability Sampled1D +OpCapability ImageQuery +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %90 "fragment_shader" %88 +OpExecutionMode %90 OriginUpperLeft +%3 = OpString "bounds-check-image-restrict-unsigned.wgsl" +OpSource Unknown 0 %3 "@group(0) @binding(0) +var image_1d: texture_1d; + +fn test_textureLoad_1d(coords: u32, level: u32) -> vec4 { + return textureLoad(image_1d, coords, level); +} + +@group(0) @binding(1) +var image_2d: texture_2d; + +fn test_textureLoad_2d(coords: vec2, level: u32) -> vec4 { + return textureLoad(image_2d, coords, level); +} + +@group(0) @binding(2) +var image_2d_array: texture_2d_array; + +fn test_textureLoad_2d_array(coords: vec2, index: i32, level: u32) -> vec4 { + return textureLoad(image_2d_array, coords, index, level); +} + +@group(0) @binding(3) +var image_depth_2d: texture_depth_2d; + +fn test_textureLoad_depth_2d(coords: vec2, level: u32) -> f32 { + return textureLoad(image_depth_2d, coords, level); +} + +@fragment +fn fragment_shader() -> @location(0) vec4 { + test_textureLoad_1d(0u, 0u); + test_textureLoad_2d(vec2(), 0u); + test_textureLoad_2d_array(vec2(), 0, 0u); + test_textureLoad_depth_2d(vec2(), 0u); + return vec4(0.,0.,0.,0.); +} +" +OpName %13 "image_1d" +OpName %15 "image_2d" +OpName %17 "image_2d_array" +OpName %19 "image_depth_2d" +OpName %22 "coords" +OpName %23 "level" +OpName %24 "test_textureLoad_1d" +OpName %38 "coords" +OpName %39 "level" +OpName %40 "test_textureLoad_2d" +OpName %53 "coords" +OpName %54 "index" +OpName %55 "level" +OpName %56 "test_textureLoad_2d_array" +OpName %72 "coords" +OpName %73 "level" +OpName %74 "test_textureLoad_depth_2d" +OpName %90 "fragment_shader" +OpDecorate %13 DescriptorSet 0 +OpDecorate %13 Binding 0 +OpDecorate %15 DescriptorSet 0 +OpDecorate %15 Binding 1 +OpDecorate %17 DescriptorSet 0 +OpDecorate %17 Binding 2 +OpDecorate %19 DescriptorSet 0 +OpDecorate %19 Binding 3 +OpDecorate %88 Location 0 +%2 = OpTypeVoid +%4 = OpTypeFloat 32 +%5 = OpTypeImage %4 1D 0 0 0 1 Unknown +%6 = OpTypeInt 32 0 +%7 = OpTypeVector %4 4 +%8 = OpTypeImage %4 2D 0 0 0 1 Unknown +%9 = OpTypeVector %6 2 +%10 = OpTypeImage %4 2D 0 1 0 1 Unknown +%11 = OpTypeInt 32 1 +%12 = OpTypeImage %4 2D 1 0 0 1 Unknown +%14 = OpTypePointer UniformConstant %5 +%13 = OpVariable %14 UniformConstant +%16 = OpTypePointer UniformConstant %8 +%15 = OpVariable %16 UniformConstant +%18 = OpTypePointer UniformConstant %10 +%17 = OpVariable %18 UniformConstant +%20 = OpTypePointer UniformConstant %12 +%19 = OpVariable %20 UniformConstant +%25 = OpTypeFunction %7 %6 %6 +%29 = OpConstant %11 1 +%33 = OpConstant %6 1 +%41 = OpTypeFunction %7 %9 %6 +%48 = OpConstantComposite %9 %33 %33 +%57 = OpTypeFunction %7 %9 %11 %6 +%61 = OpTypeVector %6 3 +%67 = OpConstantComposite %61 %33 %33 %33 +%75 = OpTypeFunction %4 %9 %6 +%82 = OpConstantComposite %9 %33 %33 +%89 = OpTypePointer Output %7 +%88 = OpVariable %89 Output +%91 = OpTypeFunction %2 +%96 = OpConstant %6 0 +%97 = OpConstantNull %9 +%98 = OpConstant %11 0 +%99 = OpConstant %4 0 +%100 = OpConstantComposite %7 %99 %99 %99 %99 +%24 = OpFunction %7 None %25 +%22 = OpFunctionParameter %6 +%23 = OpFunctionParameter %6 +%21 = OpLabel +%26 = OpLoad %5 %13 +OpBranch %27 +%27 = OpLabel +OpLine %3 5 11 +%28 = OpImageQueryLevels %11 %26 +%30 = OpISub %11 %28 %29 +%31 = OpExtInst %11 %1 UMin %23 %30 +%32 = OpImageQuerySizeLod %6 %26 %31 +%34 = OpISub %6 %32 %33 +%35 = OpExtInst %6 %1 UMin %22 %34 +%36 = OpImageFetch %7 %26 %35 Lod %31 +OpReturnValue %36 +OpFunctionEnd +%40 = OpFunction %7 None %41 +%38 = OpFunctionParameter %9 +%39 = OpFunctionParameter %6 +%37 = OpLabel +%42 = OpLoad %8 %15 +OpBranch %43 +%43 = OpLabel +OpLine %3 12 11 +%44 = OpImageQueryLevels %11 %42 +%45 = OpISub %11 %44 %29 +%46 = OpExtInst %11 %1 UMin %39 %45 +%47 = OpImageQuerySizeLod %9 %42 %46 +%49 = OpISub %9 %47 %48 +%50 = OpExtInst %9 %1 UMin %38 %49 +%51 = OpImageFetch %7 %42 %50 Lod %46 +OpReturnValue %51 +OpFunctionEnd +%56 = OpFunction %7 None %57 +%53 = OpFunctionParameter %9 +%54 = OpFunctionParameter %11 +%55 = OpFunctionParameter %6 +%52 = OpLabel +%58 = OpLoad %10 %17 +OpBranch %59 +%59 = OpLabel +OpLine %3 19 11 +%60 = OpBitcast %6 %54 +%62 = OpCompositeConstruct %61 %53 %60 +%63 = OpImageQueryLevels %11 %58 +%64 = OpISub %11 %63 %29 +%65 = OpExtInst %11 %1 UMin %55 %64 +%66 = OpImageQuerySizeLod %61 %58 %65 +%68 = OpISub %61 %66 %67 +%69 = OpExtInst %61 %1 UMin %62 %68 +%70 = OpImageFetch %7 %58 %69 Lod %65 +OpReturnValue %70 +OpFunctionEnd +%74 = OpFunction %4 None %75 +%72 = OpFunctionParameter %9 +%73 = OpFunctionParameter %6 +%71 = OpLabel +%76 = OpLoad %12 %19 +OpBranch %77 +%77 = OpLabel +OpLine %3 26 11 +%78 = OpImageQueryLevels %11 %76 +%79 = OpISub %11 %78 %29 +%80 = OpExtInst %11 %1 UMin %73 %79 +%81 = OpImageQuerySizeLod %9 %76 %80 +%83 = OpISub %9 %81 %82 +%84 = OpExtInst %9 %1 UMin %72 %83 +%85 = OpImageFetch %7 %76 %84 Lod %80 +%86 = OpCompositeExtract %4 %85 0 +OpReturnValue %86 +OpFunctionEnd +%90 = OpFunction %2 None %91 +%87 = OpLabel +%92 = OpLoad %5 %13 +%93 = OpLoad %8 %15 +%94 = OpLoad %10 %17 +%95 = OpLoad %12 %19 +OpBranch %101 +%101 = OpLabel +OpLine %3 31 5 +%102 = OpFunctionCall %7 %24 %96 %96 +OpLine %3 32 5 +%103 = OpFunctionCall %7 %40 %97 %96 +OpLine %3 33 5 +%104 = OpFunctionCall %7 %56 %97 %98 %96 +OpLine %3 34 5 +%105 = OpFunctionCall %4 %74 %97 %96 +OpLine %3 35 12 +OpStore %88 %100 +OpReturn +OpFunctionEnd \ No newline at end of file diff --git a/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm.glsl b/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm.glsl new file mode 100644 index 000000000..f2455c531 --- /dev/null +++ b/naga/tests/out/spv/wgsl-bounds-check-image-restrict-unsigned.spvasm.glsl @@ -0,0 +1,39 @@ +#version 460 +#extension GL_EXT_samplerless_texture_functions : require + +layout(set = 0, binding = 0) uniform texture1D image_1d; +layout(set = 0, binding = 1) uniform texture2D image_2d; +layout(set = 0, binding = 2) uniform texture2DArray image_2d_array; +layout(set = 0, binding = 3) uniform texture2D image_depth_2d; + +layout(location = 0) out vec4 _88; + +vec4 test_textureLoad_1d(uint coords, uint level) +{ + int _31 = int(min(level, uint(textureQueryLevels(image_1d) - 1))); + return texelFetch(image_1d, int(min(coords, (uint(textureSize(image_1d, _31)) - 1u))), _31); +} + +vec4 test_textureLoad_2d(uvec2 coords, uint level) +{ + int _46 = int(min(level, uint(textureQueryLevels(image_2d) - 1))); + return texelFetch(image_2d, ivec2(min(coords, (uvec2(textureSize(image_2d, _46)) - uvec2(1u)))), _46); +} + +vec4 test_textureLoad_2d_array(uvec2 coords, int index, uint level) +{ + int _65 = int(min(level, uint(textureQueryLevels(image_2d_array) - 1))); + return texelFetch(image_2d_array, ivec3(min(uvec3(coords, uint(index)), (uvec3(textureSize(image_2d_array, _65)) - uvec3(1u)))), _65); +} + +float test_textureLoad_depth_2d(uvec2 coords, uint level) +{ + int _80 = int(min(level, uint(textureQueryLevels(image_depth_2d) - 1))); + return texelFetch(image_depth_2d, ivec2(min(coords, (uvec2(textureSize(image_depth_2d, _80)) - uvec2(1u)))), _80).x; +} + +void main() +{ + _88 = vec4(0.0); +} +