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 29 namespace vkt 30 { 31 namespace SpirVAssembly 32 { 33 34 using namespace vk; 35 using std::map; 36 using std::string; 37 using std::vector; 38 using tcu::IVec3; 39 using tcu::RGBA; 40 using tcu::Vec4; 41 42 namespace 43 { 44 45 void addComputeUboMatrixPaddingTest (tcu::TestCaseGroup* group) 46 { 47 tcu::TestContext& testCtx = group->getTestContext(); 48 de::Random rnd (deStringHash(group->getName())); 49 const int numElements = 128; 50 51 // Read input UBO containing and array of mat2x2 using no padding inside matrix. Output 52 // into output buffer containing floats. The input and output buffer data should match. 53 const string shaderSource = 54 " OpCapability Shader\n" 55 " %1 = OpExtInstImport \"GLSL.std.450\"\n" 56 " OpMemoryModel Logical GLSL450\n" 57 " OpEntryPoint GLCompute %main \"main\" %id\n" 58 " OpExecutionMode %main LocalSize 1 1 1\n" 59 " OpSource GLSL 430\n" 60 " OpDecorate %id BuiltIn GlobalInvocationId\n" 61 " OpDecorate %_arr_v4 ArrayStride 16\n" 62 " OpMemberDecorate %Output 0 Offset 0\n" 63 " OpDecorate %Output BufferBlock\n" 64 " OpDecorate %dataOutput DescriptorSet 0\n" 65 " OpDecorate %dataOutput Binding 1\n" 66 " OpDecorate %_arr_mat2v2 ArrayStride 16\n" 67 " OpMemberDecorate %Input 0 ColMajor\n" 68 " OpMemberDecorate %Input 0 Offset 0\n" 69 " OpMemberDecorate %Input 0 MatrixStride 8\n" 70 " OpDecorate %Input Block\n" 71 " OpDecorate %dataInput DescriptorSet 0\n" 72 " OpDecorate %dataInput Binding 0\n" 73 " %void = OpTypeVoid\n" 74 " %3 = OpTypeFunction %void\n" 75 " %u32 = OpTypeInt 32 0\n" 76 " %_ptr_Function_uint = OpTypePointer Function %u32\n" 77 " %v3uint = OpTypeVector %u32 3\n" 78 " %_ptr_Input_v3uint = OpTypePointer Input %v3uint\n" 79 " %id = OpVariable %_ptr_Input_v3uint Input\n" 80 " %i32 = OpTypeInt 32 1\n" 81 " %int_0 = OpConstant %i32 0\n" 82 " %int_1 = OpConstant %i32 1\n" 83 " %uint_0 = OpConstant %u32 0\n" 84 " %uint_1 = OpConstant %u32 1\n" 85 " %uint_2 = OpConstant %u32 2\n" 86 " %uint_3 = OpConstant %u32 3\n" 87 " %_ptr_Input_uint = OpTypePointer Input %u32\n" 88 " %f32 = OpTypeFloat 32\n" 89 " %v4float = OpTypeVector %f32 4\n" 90 " %uint_128 = OpConstant %u32 128\n" 91 " %_arr_v4 = OpTypeArray %v4float %uint_128\n" 92 " %Output = OpTypeStruct %_arr_v4\n" 93 "%_ptr_Uniform_Output = OpTypePointer Uniform %Output\n" 94 " %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n" 95 " %v2float = OpTypeVector %f32 2\n" 96 " %mat2v2float = OpTypeMatrix %v2float 2\n" 97 " %_arr_mat2v2 = OpTypeArray %mat2v2float %uint_128\n" 98 " %Input = OpTypeStruct %_arr_mat2v2\n" 99 " %_ptr_Uniform_Input = OpTypePointer Uniform %Input\n" 100 " %dataInput = OpVariable %_ptr_Uniform_Input Uniform\n" 101 " %_ptr_Uniform_float = OpTypePointer Uniform %f32\n" 102 " %main = OpFunction %void None %3\n" 103 " %5 = OpLabel\n" 104 " %i = OpVariable %_ptr_Function_uint Function\n" 105 " %14 = OpAccessChain %_ptr_Input_uint %id %uint_0\n" 106 " %15 = OpLoad %u32 %14\n" 107 " OpStore %i %15\n" 108 " %idx = OpLoad %u32 %i\n" 109 " %34 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_0 %uint_0\n" 110 " %35 = OpLoad %f32 %34\n" 111 " %36 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_0\n" 112 " OpStore %36 %35\n" 113 " %40 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_0 %uint_1\n" 114 " %41 = OpLoad %f32 %40\n" 115 " %42 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_1\n" 116 " OpStore %42 %41\n" 117 " %46 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_1 %uint_0\n" 118 " %47 = OpLoad %f32 %46\n" 119 " %49 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_2\n" 120 " OpStore %49 %47\n" 121 " %52 = OpAccessChain %_ptr_Uniform_float %dataInput %int_0 %idx %int_1 %uint_1\n" 122 " %53 = OpLoad %f32 %52\n" 123 " %55 = OpAccessChain %_ptr_Uniform_float %dataOutput %int_0 %idx %uint_3\n" 124 " OpStore %55 %53\n" 125 " OpReturn\n" 126 " OpFunctionEnd\n"; 127 128 vector<tcu::Vec4> inputData; 129 ComputeShaderSpec spec; 130 131 inputData.reserve(numElements); 132 for (deUint32 numIdx = 0; numIdx < numElements; ++numIdx) 133 inputData.push_back(tcu::Vec4(rnd.getFloat(), rnd.getFloat(), rnd.getFloat(), rnd.getFloat())); 134 135 spec.assembly = shaderSource; 136 spec.numWorkGroups = IVec3(numElements, 1, 1); 137 spec.inputTypes[0] = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 138 139 spec.inputs.push_back(BufferSp(new Vec4Buffer(inputData))); 140 // Shader is expected to pass the input data by treating the input vec4 as mat2x2 141 spec.outputs.push_back(BufferSp(new Vec4Buffer(inputData))); 142 143 group->addChild(new SpvAsmComputeShaderCase(testCtx, "mat2x2", "Tests mat2x2 member in UBO struct without padding (treated as vec4).", spec)); 144 } 145 } 146 147 void addGraphicsUboMatrixPaddingTest (tcu::TestCaseGroup* group) 148 { 149 de::Random rnd (deStringHash(group->getName())); 150 map<string, string> fragments; 151 const deUint32 numDataPoints = 128; 152 RGBA defaultColors[4]; 153 GraphicsResources resources; 154 vector<tcu::Vec4> inputData; 155 156 inputData.reserve(numDataPoints); 157 for (deUint32 numIdx = 0; numIdx < numDataPoints; ++numIdx) 158 inputData.push_back(tcu::Vec4(rnd.getFloat(), rnd.getFloat(), rnd.getFloat(), rnd.getFloat())); 159 160 resources.inputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, BufferSp(new Vec4Buffer(inputData)))); 161 // Shader is expected to pass the input data by treating the input vec4 as mat2x2 162 resources.outputs.push_back(std::make_pair(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, BufferSp(new Vec4Buffer(inputData)))); 163 164 getDefaultColors(defaultColors); 165 166 fragments["pre_main"] = 167 " %uint_128 = OpConstant %u32 128\n" 168 " %_arr_v4f_uint_128 = OpTypeArray %v4f32 %uint_128\n" 169 " %Output = OpTypeStruct %_arr_v4f_uint_128\n" 170 " %_ptr_Uniform_Output = OpTypePointer Uniform %Output\n" 171 " %dataOutput = OpVariable %_ptr_Uniform_Output Uniform\n" 172 " %mat2v2f = OpTypeMatrix %v2f32 2\n" 173 "%_arr_mat2v2f_uint_128 = OpTypeArray %mat2v2f %uint_128\n" 174 " %Input = OpTypeStruct %_arr_mat2v2f_uint_128\n" 175 " %_ptr_Uniform_Input = OpTypePointer Uniform %Input\n" 176 " %dataInput = OpVariable %_ptr_Uniform_Input Uniform\n" 177 " %_ptr_Uniform_f = OpTypePointer Uniform %f32\n" 178 " %c_i32_128 = OpConstant %i32 128\n"; 179 180 fragments["decoration"] = 181 " OpDecorate %_arr_v4f_uint_128 ArrayStride 16\n" 182 " OpMemberDecorate %Output 0 Offset 0\n" 183 " OpDecorate %Output BufferBlock\n" 184 " OpDecorate %dataOutput DescriptorSet 0\n" 185 " OpDecorate %dataOutput Binding 1\n" 186 " OpDecorate %_arr_mat2v2f_uint_128 ArrayStride 16\n" 187 " OpMemberDecorate %Input 0 ColMajor\n" 188 " OpMemberDecorate %Input 0 Offset 0\n" 189 " OpMemberDecorate %Input 0 MatrixStride 8\n" 190 " OpDecorate %Input Block\n" 191 " OpDecorate %dataInput DescriptorSet 0\n" 192 " OpDecorate %dataInput Binding 0\n"; 193 194 // Read input UBO containing and array of mat2x2 using no padding inside matrix. Output 195 // into output buffer containing floats. The input and output buffer data should match. 196 // The whole array is handled inside a for loop. 197 fragments["testfun"] = 198 " %test_code = OpFunction %v4f32 None %v4f32_function\n" 199 " %param = OpFunctionParameter %v4f32\n" 200 201 " %entry = OpLabel\n" 202 " %i = OpVariable %fp_i32 Function\n" 203 " OpStore %i %c_i32_0\n" 204 " OpBranch %loop\n" 205 206 " %loop = OpLabel\n" 207 " %15 = OpLoad %i32 %i\n" 208 " %lt = OpSLessThan %bool %15 %c_i32_128\n" 209 " OpLoopMerge %merge %inc None\n" 210 " OpBranchConditional %lt %write %merge\n" 211 212 " %write = OpLabel\n" 213 " %30 = OpLoad %i32 %i\n" 214 " %34 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_0 %c_u32_0\n" 215 " %35 = OpLoad %f32 %34\n" 216 " %36 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_0\n" 217 " OpStore %36 %35\n" 218 " %40 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_0 %c_u32_1\n" 219 " %41 = OpLoad %f32 %40\n" 220 " %42 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_1\n" 221 " OpStore %42 %41\n" 222 " %46 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_1 %c_u32_0\n" 223 " %47 = OpLoad %f32 %46\n" 224 " %49 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_2\n" 225 " OpStore %49 %47\n" 226 " %52 = OpAccessChain %_ptr_Uniform_f %dataInput %c_i32_0 %30 %c_i32_1 %c_u32_1\n" 227 " %53 = OpLoad %f32 %52\n" 228 " %55 = OpAccessChain %_ptr_Uniform_f %dataOutput %c_i32_0 %30 %c_u32_3\n" 229 " OpStore %55 %53\n" 230 " OpBranch %inc\n" 231 232 " %inc = OpLabel\n" 233 " %37 = OpLoad %i32 %i\n" 234 " %39 = OpIAdd %i32 %37 %c_i32_1\n" 235 " OpStore %i %39\n" 236 " OpBranch %loop\n" 237 238 " %merge = OpLabel\n" 239 " OpReturnValue %param\n" 240 241 " OpFunctionEnd\n"; 242 243 resources.inputs.back().first = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 244 245 createTestsForAllStages("mat2x2", defaultColors, defaultColors, fragments, resources, vector<string>(), group); 246 } 247 248 tcu::TestCaseGroup* createUboMatrixPaddingComputeGroup (tcu::TestContext& testCtx) 249 { 250 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "ubo_padding", "Compute tests for UBO struct member packing.")); 251 addComputeUboMatrixPaddingTest(group.get()); 252 253 return group.release(); 254 } 255 256 tcu::TestCaseGroup* createUboMatrixPaddingGraphicsGroup (tcu::TestContext& testCtx) 257 { 258 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "ubo_padding", "Graphics tests for UBO struct member packing.")); 259 addGraphicsUboMatrixPaddingTest(group.get()); 260 261 return group.release(); 262 } 263 264 } // SpirVAssembly 265 } // vkt 266