1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V Assembly Tests for UBO matrix padding.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmUboMatrixPaddingTests.hpp"
25 #include "vktSpvAsmComputeShaderCase.hpp"
26 #include "vktSpvAsmComputeShaderTestUtil.hpp"
27 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
28 #include "tcuVectorUtil.hpp"
29 
30 namespace vkt
31 {
32 namespace SpirVAssembly
33 {
34 
35 using namespace vk;
36 using std::map;
37 using std::string;
38 using std::vector;
39 using tcu::IVec3;
40 using tcu::RGBA;
41 using tcu::Vec4;
42 
43 namespace
44 {
45 
addComputeUboMatrixPaddingTest(tcu::TestCaseGroup * group)46 void addComputeUboMatrixPaddingTest(tcu::TestCaseGroup *group)
47 {
48     tcu::TestContext &testCtx = group->getTestContext();
49     de::Random rnd(deStringHash(group->getName()));
50     const int numElements = 128;
51 
52     // Read input UBO containing and array of mat2x2 using no padding inside matrix. Output
53     // into output buffer containing floats. The input and output buffer data should match.
54     const string shaderSource =
55         "                       OpCapability Shader\n"
56         "                  %1 = OpExtInstImport \"GLSL.std.450\"\n"
57         "                       OpMemoryModel Logical GLSL450\n"
58         "                       OpEntryPoint GLCompute %main \"main\" %id\n"
59         "                       OpExecutionMode %main LocalSize 1 1 1\n"
60         "                       OpSource GLSL 430\n"
61         "                       OpDecorate %id BuiltIn GlobalInvocationId\n"
62         "                       OpDecorate %_arr_v4 ArrayStride 16\n"
63         "                       OpMemberDecorate %Output 0 Offset 0\n"
64         "                       OpDecorate %Output BufferBlock\n"
65         "                       OpDecorate %dataOutput DescriptorSet 0\n"
66         "                       OpDecorate %dataOutput Binding 1\n"
67         "                       OpDecorate %_arr_mat2v2 ArrayStride 16\n"
68         "                       OpMemberDecorate %Input 0 ColMajor\n"
69         "                       OpMemberDecorate %Input 0 Offset 0\n"
70         "                       OpMemberDecorate %Input 0 MatrixStride 8\n"
71         "                       OpDecorate %Input Block\n"
72         "                       OpDecorate %dataInput DescriptorSet 0\n"
73         "                       OpDecorate %dataInput Binding 0\n"
74         "               %void = OpTypeVoid\n"
75         "                  %3 = OpTypeFunction %void\n"
76         "                %u32 = OpTypeInt 32 0\n"
77         " %_ptr_Function_uint = OpTypePointer Function %u32\n"
78         "             %v3uint = OpTypeVector %u32 3\n"
79         "  %_ptr_Input_v3uint = OpTypePointer Input %v3uint\n"
80         "                 %id = OpVariable %_ptr_Input_v3uint Input\n"
81         "                %i32 = OpTypeInt 32 1\n"
82         "              %int_0 = OpConstant %i32 0\n"
83         "              %int_1 = OpConstant %i32 1\n"
84         "             %uint_0 = OpConstant %u32 0\n"
85         "             %uint_1 = OpConstant %u32 1\n"
86         "             %uint_2 = OpConstant %u32 2\n"
87         "             %uint_3 = OpConstant %u32 3\n"
88         "    %_ptr_Input_uint = OpTypePointer Input %u32\n"
89         "                %f32 = OpTypeFloat 32\n"
90         "            %v4float = OpTypeVector %f32 4\n"
91         "           %uint_128 = OpConstant %u32 128\n"
92         "            %_arr_v4 = OpTypeArray %v4float %uint_128\n"
93         "             %Output = OpTypeStruct %_arr_v4\n"
94         "%_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
95         "         %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
96         "            %v2float = OpTypeVector %f32 2\n"
97         "        %mat2v2float = OpTypeMatrix %v2float 2\n"
98         "        %_arr_mat2v2 = OpTypeArray %mat2v2float %uint_128\n"
99         "              %Input = OpTypeStruct %_arr_mat2v2\n"
100         " %_ptr_Uniform_Input = OpTypePointer Uniform %Input\n"
101         "          %dataInput = OpVariable %_ptr_Uniform_Input Uniform\n"
102         " %_ptr_Uniform_float = OpTypePointer Uniform %f32\n"
103         "               %main = OpFunction %void None %3\n"
104         "                  %5 = OpLabel\n"
105         "                  %i = OpVariable %_ptr_Function_uint Function\n"
106         "                 %14 = OpAccessChain %_ptr_Input_uint %id %uint_0\n"
107         "                 %15 = OpLoad %u32 %14\n"
108         "                       OpStore %i %15\n"
109         "                %idx = OpLoad %u32 %i\n"
110         "                 %34 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_0 %uint_0\n"
111         "                 %35 = OpLoad %f32 %34\n"
112         "                 %36 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_0\n"
113         "                       OpStore %36 %35\n"
114         "                 %40 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_0 %uint_1\n"
115         "                 %41 = OpLoad %f32 %40\n"
116         "                 %42 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_1\n"
117         "                       OpStore %42 %41\n"
118         "                 %46 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_1 %uint_0\n"
119         "                 %47 = OpLoad %f32 %46\n"
120         "                 %49 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_2\n"
121         "                       OpStore %49 %47\n"
122         "                 %52 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_1 %uint_1\n"
123         "                 %53 = OpLoad %f32 %52\n"
124         "                 %55 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_3\n"
125         "                       OpStore %55 %53\n"
126         "                       OpReturn\n"
127         "                       OpFunctionEnd\n";
128 
129     vector<tcu::Vec4> inputData;
130     ComputeShaderSpec spec;
131 
132     inputData.reserve(numElements);
133     for (uint32_t numIdx = 0; numIdx < numElements; ++numIdx)
134         inputData.push_back(tcu::randomVec4(rnd));
135 
136     spec.assembly      = shaderSource;
137     spec.numWorkGroups = IVec3(numElements, 1, 1);
138 
139     spec.inputs.push_back(Resource(BufferSp(new Vec4Buffer(inputData)), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER));
140     // Shader is expected to pass the input data by treating the input vec4 as mat2x2
141     spec.outputs.push_back(Resource(BufferSp(new Vec4Buffer(inputData))));
142 
143     group->addChild(new SpvAsmComputeShaderCase(testCtx, "mat2x2", spec));
144 }
145 
addGraphicsUboMatrixPaddingTest(tcu::TestCaseGroup * group)146 void addGraphicsUboMatrixPaddingTest(tcu::TestCaseGroup *group)
147 {
148     de::Random rnd(deStringHash(group->getName()));
149     map<string, string> fragments;
150     const uint32_t numDataPoints = 128;
151     RGBA defaultColors[4];
152     GraphicsResources resources;
153 
154     SpecConstants noSpecConstants;
155     PushConstants noPushConstants;
156     GraphicsInterfaces noInterfaces;
157     std::vector<std::string> noExtensions;
158     VulkanFeatures vulkanFeatures = VulkanFeatures();
159 
160     vector<tcu::Vec4> inputData(numDataPoints);
161     for (uint32_t numIdx = 0; numIdx < numDataPoints; ++numIdx)
162         inputData[numIdx] = tcu::randomVec4(rnd);
163 
164     resources.inputs.push_back(Resource(BufferSp(new Vec4Buffer(inputData)), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER));
165     // Shader is expected to pass the input data by treating the input vec4 as mat2x2
166     resources.outputs.push_back(Resource(BufferSp(new Vec4Buffer(inputData)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
167 
168     getDefaultColors(defaultColors);
169 
170     fragments["pre_main"] = "             %uint_128 = OpConstant %u32 128\n"
171                             "    %_arr_v4f_uint_128 = OpTypeArray %v4f32 %uint_128\n"
172                             "               %Output = OpTypeStruct %_arr_v4f_uint_128\n"
173                             "  %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n"
174                             "           %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n"
175                             "              %mat2v2f = OpTypeMatrix %v2f32 2\n"
176                             "%_arr_mat2v2f_uint_128 = OpTypeArray %mat2v2f %uint_128\n"
177                             "                %Input = OpTypeStruct %_arr_mat2v2f_uint_128\n"
178                             "   %_ptr_Uniform_Input = OpTypePointer Uniform %Input\n"
179                             "            %dataInput = OpVariable %_ptr_Uniform_Input Uniform\n"
180                             "       %_ptr_Uniform_f = OpTypePointer Uniform %f32\n"
181                             "            %c_i32_128 = OpConstant %i32 128\n";
182 
183     fragments["decoration"] = "                         OpDecorate %_arr_v4f_uint_128 ArrayStride 16\n"
184                               "                         OpMemberDecorate %Output 0 Offset 0\n"
185                               "                         OpDecorate %Output BufferBlock\n"
186                               "                         OpDecorate %dataOutput DescriptorSet 0\n"
187                               "                         OpDecorate %dataOutput Binding 1\n"
188                               "                         OpDecorate %_arr_mat2v2f_uint_128 ArrayStride 16\n"
189                               "                         OpMemberDecorate %Input 0 ColMajor\n"
190                               "                         OpMemberDecorate %Input 0 Offset 0\n"
191                               "                         OpMemberDecorate %Input 0 MatrixStride 8\n"
192                               "                         OpDecorate %Input Block\n"
193                               "                         OpDecorate %dataInput DescriptorSet 0\n"
194                               "                         OpDecorate %dataInput Binding 0\n";
195 
196     // Read input UBO containing and array of mat2x2 using no padding inside matrix. Output
197     // into output buffer containing floats. The input and output buffer data should match.
198     // The whole array is handled inside a for loop.
199     fragments["testfun"] =
200         "            %test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
201         "                %param = OpFunctionParameter %v4f32\n"
202 
203         "                %entry = OpLabel\n"
204         "                    %i = OpVariable %fp_i32 Function\n"
205         "                         OpStore %i %c_i32_0\n"
206         "                         OpBranch %loop\n"
207 
208         "                 %loop = OpLabel\n"
209         "                   %15 = OpLoad %i32 %i\n"
210         "                   %lt = OpSLessThan %bool %15 %c_i32_128\n"
211         "                         OpLoopMerge %merge %inc None\n"
212         "                         OpBranchConditional %lt %write %merge\n"
213 
214         "                %write = OpLabel\n"
215         "                   %30 = OpLoad %i32 %i\n"
216         "                   %34 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_0 %c_u32_0\n"
217         "                   %35 = OpLoad %f32 %34\n"
218         "                   %36 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_0\n"
219         "                         OpStore %36 %35\n"
220         "                   %40 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_0 %c_u32_1\n"
221         "                   %41 = OpLoad %f32 %40\n"
222         "                   %42 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_1\n"
223         "                         OpStore %42 %41\n"
224         "                   %46 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_1 %c_u32_0\n"
225         "                   %47 = OpLoad %f32 %46\n"
226         "                   %49 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_2\n"
227         "                         OpStore %49 %47\n"
228         "                   %52 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_1 %c_u32_1\n"
229         "                   %53 = OpLoad %f32 %52\n"
230         "                   %55 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_3\n"
231         "                         OpStore %55 %53\n"
232         "                         OpBranch %inc\n"
233 
234         "                  %inc = OpLabel\n"
235         "                   %37 = OpLoad %i32 %i\n"
236         "                   %39 = OpIAdd %i32 %37 %c_i32_1\n"
237         "                         OpStore %i %39\n"
238         "                         OpBranch %loop\n"
239 
240         "                %merge = OpLabel\n"
241         "                         OpReturnValue %param\n"
242 
243         "                         OpFunctionEnd\n";
244 
245     resources.inputs.back().setDescriptorType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
246 
247     vulkanFeatures.coreFeatures.vertexPipelineStoresAndAtomics = true;
248     vulkanFeatures.coreFeatures.fragmentStoresAndAtomics       = false;
249     createTestForStage(VK_SHADER_STAGE_VERTEX_BIT, "mat2x2_vert", defaultColors, defaultColors, fragments,
250                        noSpecConstants, noPushConstants, resources, noInterfaces, noExtensions, vulkanFeatures, group);
251 
252     createTestForStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "mat2x2_tessc", defaultColors, defaultColors,
253                        fragments, noSpecConstants, noPushConstants, resources, noInterfaces, noExtensions,
254                        vulkanFeatures, group);
255 
256     createTestForStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "mat2x2_tesse", defaultColors, defaultColors,
257                        fragments, noSpecConstants, noPushConstants, resources, noInterfaces, noExtensions,
258                        vulkanFeatures, group);
259 
260     createTestForStage(VK_SHADER_STAGE_GEOMETRY_BIT, "mat2x2_geom", defaultColors, defaultColors, fragments,
261                        noSpecConstants, noPushConstants, resources, noInterfaces, noExtensions, vulkanFeatures, group);
262 
263     vulkanFeatures.coreFeatures.vertexPipelineStoresAndAtomics = false;
264     vulkanFeatures.coreFeatures.fragmentStoresAndAtomics       = true;
265     createTestForStage(VK_SHADER_STAGE_FRAGMENT_BIT, "mat2x2_frag", defaultColors, defaultColors, fragments,
266                        noSpecConstants, noPushConstants, resources, noInterfaces, noExtensions, vulkanFeatures, group);
267 }
268 
269 } // namespace
270 
createUboMatrixPaddingComputeGroup(tcu::TestContext & testCtx)271 tcu::TestCaseGroup *createUboMatrixPaddingComputeGroup(tcu::TestContext &testCtx)
272 {
273     // Compute tests for UBO struct member packing.
274     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "ubo_padding"));
275     addComputeUboMatrixPaddingTest(group.get());
276 
277     return group.release();
278 }
279 
createUboMatrixPaddingGraphicsGroup(tcu::TestContext & testCtx)280 tcu::TestCaseGroup *createUboMatrixPaddingGraphicsGroup(tcu::TestContext &testCtx)
281 {
282     // Graphics tests for UBO struct member packing.
283     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "ubo_padding"));
284     addGraphicsUboMatrixPaddingTest(group.get());
285 
286     return group.release();
287 }
288 
289 } // namespace SpirVAssembly
290 } // namespace vkt
291