| // Copyright (c) 2024 Epic Games, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <string> |
| |
| #include "gmock/gmock.h" |
| #include "source/opt/struct_packing_pass.h" |
| #include "test/opt/pass_fixture.h" |
| #include "test/opt/pass_utils.h" |
| |
| namespace spvtools { |
| namespace opt { |
| namespace { |
| |
| using StructPackingTest = PassTest<::testing::Test>; |
| |
| TEST_F(StructPackingTest, PackSimpleStructStd140) { |
| // #version 420 |
| // |
| // layout(std140, binding = 0) uniform Globals { |
| // layout(offset = 16) vec3 a_xyz; |
| // float a_w; |
| // layout(offset = 128) vec3 b_xyz; |
| // int b_w; |
| // }; |
| // |
| // void main() {} |
| const std::string spirv = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginLowerLeft |
| OpSource GLSL 420 |
| OpName %main "main" |
| OpName %Globals "Globals" |
| OpMemberName %Globals 0 "a_xyz" |
| OpMemberName %Globals 1 "a_w" |
| OpMemberName %Globals 2 "b_xyz" |
| OpMemberName %Globals 3 "b_w" |
| OpName %_ "" |
| ; CHECK: OpMemberDecorate %Globals 0 Offset 0 |
| OpMemberDecorate %Globals 0 Offset 16 |
| ; CHECK: OpMemberDecorate %Globals 1 Offset 12 |
| OpMemberDecorate %Globals 1 Offset 28 |
| ; CHECK: OpMemberDecorate %Globals 2 Offset 16 |
| OpMemberDecorate %Globals 2 Offset 128 |
| ; CHECK: OpMemberDecorate %Globals 3 Offset 28 |
| OpMemberDecorate %Globals 3 Offset 140 |
| OpDecorate %Globals Block |
| OpDecorate %_ DescriptorSet 0 |
| OpDecorate %_ Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v3float = OpTypeVector %float 3 |
| %int = OpTypeInt 32 1 |
| %Globals = OpTypeStruct %v3float %float %v3float %int |
| %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals |
| %_ = OpVariable %_ptr_Uniform_Globals Uniform |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| SinglePassRunAndMatch<StructPackingPass>( |
| spirv, true, "Globals", StructPackingPass::PackingRules::Std140); |
| } |
| |
| TEST_F(StructPackingTest, PackSimpleStructWithPaddingStd140) { |
| // #version 420 |
| // |
| // layout(std140, binding = 0) uniform Globals { |
| // layout(offset = 16) vec3 a_xyz; |
| // float a_w; |
| // float b_x_padding_yzw; |
| // layout(offset = 128) vec3 c_xyz; |
| // int c_w; |
| // }; |
| // |
| // void main() {} |
| const std::string spirv = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginLowerLeft |
| OpSource GLSL 420 |
| OpName %main "main" |
| OpName %Globals "Globals" |
| OpMemberName %Globals 0 "a_xyz" |
| OpMemberName %Globals 1 "a_w" |
| OpMemberName %Globals 2 "b_x_padding_yzw" |
| OpMemberName %Globals 3 "c_xyz" |
| OpMemberName %Globals 4 "c_w" |
| OpName %_ "" |
| ; CHECK: OpMemberDecorate %Globals 0 Offset 0 |
| OpMemberDecorate %Globals 0 Offset 16 |
| ; CHECK: OpMemberDecorate %Globals 1 Offset 12 |
| OpMemberDecorate %Globals 1 Offset 28 |
| ; CHECK: OpMemberDecorate %Globals 2 Offset 16 |
| OpMemberDecorate %Globals 2 Offset 32 |
| ; CHECK: OpMemberDecorate %Globals 3 Offset 32 |
| OpMemberDecorate %Globals 3 Offset 128 |
| ; CHECK: OpMemberDecorate %Globals 4 Offset 44 |
| OpMemberDecorate %Globals 4 Offset 140 |
| OpDecorate %Globals Block |
| OpDecorate %_ DescriptorSet 0 |
| OpDecorate %_ Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %v3float = OpTypeVector %float 3 |
| %int = OpTypeInt 32 1 |
| %Globals = OpTypeStruct %v3float %float %float %v3float %int |
| %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals |
| %_ = OpVariable %_ptr_Uniform_Globals Uniform |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| SinglePassRunAndMatch<StructPackingPass>( |
| spirv, true, "Globals", StructPackingPass::PackingRules::Std140); |
| } |
| |
| TEST_F(StructPackingTest, PackSimpleScalarArrayStd140) { |
| // #version 420 |
| // |
| // layout(std140, binding = 0) uniform Globals { |
| // layout(offset = 16) float a[2]; |
| // layout(offset = 128) float b[2]; // Must become offset 32 with std140 |
| // }; |
| // |
| // void main() {} |
| const std::string spirv = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginLowerLeft |
| OpSource GLSL 420 |
| OpName %main "main" |
| OpName %Globals "Globals" |
| OpMemberName %Globals 0 "a" |
| OpMemberName %Globals 1 "b" |
| OpName %_ "" |
| OpDecorate %_arr_float_uint_2 ArrayStride 16 |
| OpDecorate %_arr_float_uint_2_0 ArrayStride 16 |
| ; CHECK: OpMemberDecorate %Globals 0 Offset 0 |
| OpMemberDecorate %Globals 0 Offset 16 |
| ; CHECK: OpMemberDecorate %Globals 1 Offset 32 |
| OpMemberDecorate %Globals 1 Offset 128 |
| OpDecorate %Globals Block |
| OpDecorate %_ DescriptorSet 0 |
| OpDecorate %_ Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %_arr_float_uint_2 = OpTypeArray %float %uint_2 |
| %_arr_float_uint_2_0 = OpTypeArray %float %uint_2 |
| %Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0 |
| %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals |
| %_ = OpVariable %_ptr_Uniform_Globals Uniform |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| SinglePassRunAndMatch<StructPackingPass>( |
| spirv, true, "Globals", StructPackingPass::PackingRules::Std140); |
| } |
| |
| TEST_F(StructPackingTest, PackSimpleScalarArrayStd430) { |
| // #version 430 |
| // |
| // layout(std430, binding = 0) buffer Globals { |
| // layout(offset = 16) float a[2]; |
| // layout(offset = 128) float b[2]; // Must become offset 8 with std430 |
| // }; |
| // |
| // void main() {} |
| const std::string spirv = R"( |
| OpCapability Shader |
| %1 = OpExtInstImport "GLSL.std.450" |
| OpMemoryModel Logical GLSL450 |
| OpEntryPoint Fragment %main "main" |
| OpExecutionMode %main OriginLowerLeft |
| OpSource GLSL 430 |
| OpName %main "main" |
| OpName %Globals "Globals" |
| OpMemberName %Globals 0 "a" |
| OpMemberName %Globals 1 "b" |
| OpName %_ "" |
| OpDecorate %_arr_float_uint_2 ArrayStride 4 |
| OpDecorate %_arr_float_uint_2_0 ArrayStride 4 |
| ; CHECK: OpMemberDecorate %Globals 0 Offset 0 |
| OpMemberDecorate %Globals 0 Offset 16 |
| ; CHECK: OpMemberDecorate %Globals 1 Offset 8 |
| OpMemberDecorate %Globals 1 Offset 128 |
| OpDecorate %Globals BufferBlock |
| OpDecorate %_ DescriptorSet 0 |
| OpDecorate %_ Binding 0 |
| %void = OpTypeVoid |
| %3 = OpTypeFunction %void |
| %float = OpTypeFloat 32 |
| %uint = OpTypeInt 32 0 |
| %uint_2 = OpConstant %uint 2 |
| %_arr_float_uint_2 = OpTypeArray %float %uint_2 |
| %_arr_float_uint_2_0 = OpTypeArray %float %uint_2 |
| %Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0 |
| %_ptr_Uniform_Globals = OpTypePointer Uniform %Globals |
| %_ = OpVariable %_ptr_Uniform_Globals Uniform |
| %main = OpFunction %void None %3 |
| %5 = OpLabel |
| OpReturn |
| OpFunctionEnd |
| )"; |
| |
| SinglePassRunAndMatch<StructPackingPass>( |
| spirv, true, "Globals", StructPackingPass::PackingRules::Std430); |
| } |
| |
| } // namespace |
| } // namespace opt |
| } // namespace spvtools |