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