1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 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 OpVariable initializer
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmVariableInitTests.hpp"
25 #include "vktSpvAsmComputeShaderCase.hpp"
26 #include "vktSpvAsmComputeShaderTestUtil.hpp"
27 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
28 #include "tcuStringTemplate.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::StringTemplate;
42 using tcu::Vec4;
43 
44 namespace
45 {
46 
47 enum InitializationSource
48 {
49     INITIALIZATION_SOURCE_CONSTANT, // Variable is initialized from a constant value
50     INITIALIZATION_SOURCE_GLOBAL, // Variable is initialized from a global variable, which in turn is initialized from a constant
51 };
52 
53 struct TestParams
54 {
55     string name;
56     string type;
57     int numComponents;
58     InitializationSource initializationSource;
59 };
60 
61 struct ShaderParams
62 {
63     InstanceContext context;
64     string type;
65 };
66 
67 const TestParams testParams[] = {{"float", "f32", 1, INITIALIZATION_SOURCE_CONSTANT},
68                                  {"vec4", "v4f32", 4, INITIALIZATION_SOURCE_CONSTANT},
69                                  {"matrix", "matrix", 2 * 4, INITIALIZATION_SOURCE_CONSTANT},
70                                  {"floatarray", "floatArray", 8, INITIALIZATION_SOURCE_CONSTANT},
71                                  {"struct", "struct", 2 * 4 + 4 + 4, INITIALIZATION_SOURCE_CONSTANT},
72 
73                                  {"float_from_workgroup", "f32", 1, INITIALIZATION_SOURCE_GLOBAL},
74                                  {"vec4_from_workgroup", "v4f32", 4, INITIALIZATION_SOURCE_GLOBAL},
75                                  {"matrix_from_workgroup", "matrix", 2 * 4, INITIALIZATION_SOURCE_GLOBAL},
76                                  {"floatarray_from_workgroup", "floatArray", 8, INITIALIZATION_SOURCE_GLOBAL},
77                                  {"struct_from_workgroup", "struct", 2 * 4 + 4 + 4, INITIALIZATION_SOURCE_GLOBAL}};
78 
79 const string common =
80     "                      %f32_1 = OpConstant %f32 1\n"
81     "                    %v4f32_1 = OpConstantComposite %v4f32 %f32_1 %f32_1 %f32_1 %f32_1\n"
82     "                     %matrix = OpTypeMatrix %v4f32 2\n"
83     "                   %matrix_1 = OpConstantComposite %matrix %v4f32_1 %v4f32_1\n"
84     "                     %struct = OpTypeStruct %matrix %v4f32 %f32 %f32 %f32 %f32\n"
85     "                   %struct_1 = OpConstantComposite %struct %matrix_1 %v4f32_1 %f32_1 %f32_1 %f32_1 %f32_1\n"
86     "                    %c_u32_8 = OpConstant %u32 8\n"
87     "                 %floatArray = OpTypeArray %f32 %c_u32_8\n"
88     "               %floatArray_1 = OpConstantComposite %floatArray %f32_1 %f32_1 %f32_1 %f32_1 %f32_1 %f32_1 %f32_1 "
89     "%f32_1\n"
90     "                %numElements = OpConstant %u32 ${count}\n"
91     "                %outputArray = OpTypeArray %${type} %numElements\n"
92     "                     %Output = OpTypeStruct %outputArray\n"
93     "                %_ptr_Output = OpTypePointer StorageBuffer %Output\n"
94     "                      %sbPtr = OpTypePointer StorageBuffer %${type}\n"
95     "                 %dataOutput = OpVariable %_ptr_Output StorageBuffer\n";
96 
97 const string globals = "        %_ptr_${type}_global = OpTypePointer Workgroup %${type}\n"
98                        "           %${type}_global_1 = OpVariable %_ptr_${type}_global Workgroup\n";
99 
100 const string decorations = "${arrayStrideDecoration}"
101                            "                               OpMemberDecorate %Output 0 Offset 0\n"
102                            "                               OpDecorate %Output Block\n"
103                            "                               OpDecorate %dataOutput DescriptorSet 0\n"
104                            "                               OpDecorate %dataOutput Binding 0\n"
105                            "${extraDecorations:opt}"
106                            "                               OpDecorate %floatArray ArrayStride 4\n"
107                            "                               OpMemberDecorate %struct 0 ColMajor\n"
108                            "                               OpMemberDecorate %struct 0 Offset 0\n"
109                            "                               OpMemberDecorate %struct 0 MatrixStride 16\n"
110                            "                               OpMemberDecorate %struct 1 Offset 32\n"
111                            "                               OpMemberDecorate %struct 2 Offset 48\n"
112                            "                               OpMemberDecorate %struct 3 Offset 52\n"
113                            "                               OpMemberDecorate %struct 4 Offset 56\n"
114                            "                               OpMemberDecorate %struct 5 Offset 60\n";
115 
addComputeVariableInitPrivateTest(tcu::TestCaseGroup * group)116 void addComputeVariableInitPrivateTest(tcu::TestCaseGroup *group)
117 {
118     tcu::TestContext &testCtx        = group->getTestContext();
119     const int numFloats              = 128;
120     tcu::TestCaseGroup *privateGroup = new tcu::TestCaseGroup(testCtx, "private");
121     vector<float> expectedOutput(numFloats, 1.0f);
122 
123     group->addChild(privateGroup);
124 
125     for (int paramIdx = 0; paramIdx < DE_LENGTH_OF_ARRAY(testParams); paramIdx++)
126     {
127         ComputeShaderSpec spec;
128         spec.outputs.push_back(BufferSp(new Float32Buffer(expectedOutput)));
129 
130         map<string, string> shaderSpec;
131         const int numComponents = testParams[paramIdx].numComponents;
132         const int numElements   = numFloats / numComponents;
133         const string type       = testParams[paramIdx].type;
134 
135         const StringTemplate shaderSourceTemplate(
136             string("                         OpCapability Shader\n"
137                    "${capabilities:opt}"
138                    "                         OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
139                    "${extensions:opt}"
140                    "                    %1 = OpExtInstImport \"GLSL.std.450\"\n"
141                    "                         OpMemoryModel Logical GLSL450\n"
142                    "                         OpEntryPoint GLCompute %main \"main\" %gl_GlobalInvocationID\n"
143                    "                         OpExecutionMode %main LocalSize 1 1 1\n"
144                    "                         OpSource GLSL 430\n"
145                    "                         OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId\n") +
146             decorations +
147             string("                 %void = OpTypeVoid\n"
148                    "             %voidFunc = OpTypeFunction %void\n"
149                    "                  %f32 = OpTypeFloat 32\n"
150                    "                  %u32 = OpTypeInt 32 0\n"
151                    "              %c_u32_0 = OpConstant %u32 0\n"
152                    "                %v4f32 = OpTypeVector %f32 4\n") +
153             common + (testParams[paramIdx].initializationSource == INITIALIZATION_SOURCE_GLOBAL ? globals : "") +
154             string("              %dataPtr = OpTypePointer Private %${type}\n"
155                    "   %_ptr_Function_uint = OpTypePointer Function %u32\n"
156                    "               %v3uint = OpTypeVector %u32 3\n"
157                    "    %_ptr_Input_v3uint = OpTypePointer Input %v3uint\n"
158                    "%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input\n"
159                    "      %_ptr_Input_uint = OpTypePointer Input %u32\n"
160                    "                  %int = OpTypeInt 32 1\n"
161                    "                %int_0 = OpConstant %int 0\n"
162                    "${variableInit}"
163                    "                 %main = OpFunction %void None %voidFunc\n"
164                    "                %entry = OpLabel\n"
165                    "        %invocationPtr = OpAccessChain %_ptr_Input_uint %gl_GlobalInvocationID %c_u32_0\n"
166                    "           %invocation = OpLoad %u32 %invocationPtr\n"
167                    "${dataLoad}"
168                    "            %outputPtr = OpAccessChain %sbPtr %dataOutput %int_0 %invocation\n"
169                    "                         OpStore %outputPtr %outputData\n"
170                    "                         OpReturn\n"
171                    "                         OpFunctionEnd\n"));
172 
173         shaderSpec["type"] = type;
174 
175         shaderSpec["arrayStrideDecoration"] =
176             "OpDecorate %outputArray ArrayStride " + de::toString(numComponents * 4) + "\n";
177         shaderSpec["count"]     = de::toString(numElements);
178         shaderSpec["constData"] = type + "_1";
179 
180         switch (testParams[paramIdx].initializationSource)
181         {
182         case INITIALIZATION_SOURCE_CONSTANT:
183             shaderSpec["variableInit"] = "             %f1 = OpVariable %dataPtr Private %" + type + "_1\n";
184             shaderSpec["dataLoad"]     = "     %outputData = OpLoad %" + type + " %f1\n";
185             break;
186         default:
187             DE_ASSERT(testParams[paramIdx].initializationSource == INITIALIZATION_SOURCE_GLOBAL);
188 
189             shaderSpec["capabilities"] = "                   OpCapability VariablePointers\n";
190             shaderSpec["extensions"]   = "                   OpExtension \"SPV_KHR_variable_pointers\"\n";
191             shaderSpec["variableInit"] = "     %dataPtrPtr = OpTypePointer Private %_ptr_" + type +
192                                          "_global\n"
193                                          "             %f1 = OpVariable %dataPtrPtr Private %" +
194                                          type + "_global_1\n";
195             shaderSpec["dataLoad"] = "  %outputDataPtr = OpLoad %_ptr_" + type +
196                                      "_global %f1\n"
197                                      "                   OpStore %" +
198                                      type + "_global_1 %" + type +
199                                      "_1\n"
200                                      "     %outputData = OpLoad %" +
201                                      type + " %outputDataPtr\n";
202 
203             spec.requestedVulkanFeatures.extVariablePointers.variablePointers = true;
204             spec.extensions.push_back("VK_KHR_variable_pointers");
205             break;
206         }
207 
208         if (testParams[paramIdx].type == "matrix")
209         {
210             shaderSpec["extraDecorations"] += "                         OpMemberDecorate %Output 0 ColMajor\n"
211                                               "                         OpMemberDecorate %Output 0 MatrixStride 16\n";
212         }
213 
214         spec.assembly      = shaderSourceTemplate.specialize(shaderSpec);
215         spec.numWorkGroups = IVec3(numElements, 1, 1);
216         spec.extensions.push_back("VK_KHR_storage_buffer_storage_class");
217 
218         privateGroup->addChild(new SpvAsmComputeShaderCase(testCtx, testParams[paramIdx].name.c_str(), spec));
219     }
220 }
221 
addGraphicsVariableInitPrivateTest(tcu::TestCaseGroup * group)222 void addGraphicsVariableInitPrivateTest(tcu::TestCaseGroup *group)
223 {
224     tcu::TestContext &testCtx = group->getTestContext();
225     map<string, string> fragments;
226     RGBA defaultColors[4];
227     VulkanFeatures features;
228     tcu::TestCaseGroup *privateGroup = new tcu::TestCaseGroup(testCtx, "private");
229     const int numFloats              = 128;
230     vector<float> expectedOutput(numFloats, 1.0f);
231 
232     group->addChild(privateGroup);
233     getDefaultColors(defaultColors);
234 
235     features.coreFeatures.vertexPipelineStoresAndAtomics = true;
236     features.coreFeatures.fragmentStoresAndAtomics       = true;
237 
238     for (int paramIdx = 0; paramIdx < DE_LENGTH_OF_ARRAY(testParams); paramIdx++)
239     {
240         if (testParams[paramIdx].initializationSource != INITIALIZATION_SOURCE_CONSTANT)
241             continue;
242 
243         GraphicsResources resources;
244         vector<string> extensions;
245 
246         resources.outputs.push_back(
247             Resource(BufferSp(new Float32Buffer(expectedOutput)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
248         extensions.push_back("VK_KHR_storage_buffer_storage_class");
249 
250         map<string, string> shaderSpec;
251         const int numComponents = testParams[paramIdx].numComponents;
252         const int numElements   = numFloats / numComponents;
253         const string type       = testParams[paramIdx].type;
254 
255         StringTemplate preMain(common + string("              %dataPtr = OpTypePointer Private %${type}\n"
256                                                "${variableInit}"));
257 
258         StringTemplate decoration(decorations);
259 
260         StringTemplate testFun("            %test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
261                                "                %param = OpFunctionParameter %v4f32\n"
262                                "                %entry = OpLabel\n"
263                                "                    %i = OpVariable %fp_i32 Function\n"
264                                "${dataLoad}"
265                                "                         OpStore %i %c_i32_0\n"
266                                "                         OpBranch %loop\n"
267                                "                 %loop = OpLabel\n"
268                                "                   %15 = OpLoad %i32 %i\n"
269                                "                   %lt = OpSLessThan %bool %15 %numElements\n"
270                                "                         OpLoopMerge %merge %inc None\n"
271                                "                         OpBranchConditional %lt %write %merge\n"
272                                "                %write = OpLabel\n"
273                                "                   %30 = OpLoad %i32 %i\n"
274                                "            %outputPtr = OpAccessChain %sbPtr %dataOutput %c_i32_0 %30\n"
275                                "                         OpStore %outputPtr %outputData\n"
276                                "                         OpBranch %inc\n"
277                                "                  %inc = OpLabel\n"
278                                "                   %37 = OpLoad %i32 %i\n"
279                                "                   %39 = OpIAdd %i32 %37 %c_i32_1\n"
280                                "                         OpStore %i %39\n"
281                                "                         OpBranch %loop\n"
282                                "                %merge = OpLabel\n"
283                                "                         OpReturnValue %param\n"
284                                "                         OpFunctionEnd\n");
285 
286         shaderSpec["type"] = type;
287         shaderSpec["arrayStrideDecoration"] =
288             "OpDecorate %outputArray ArrayStride " + de::toString(numComponents * 4) + "\n";
289         shaderSpec["count"]        = de::toString(numElements);
290         shaderSpec["constData"]    = type + "_1";
291         shaderSpec["variableInit"] = "             %f1 = OpVariable %dataPtr Private %" + type + "_1\n";
292         shaderSpec["dataLoad"]     = "     %outputData = OpLoad %" + type + " %f1\n";
293 
294         if (testParams[paramIdx].type == "matrix")
295         {
296             shaderSpec["extraDecorations"] += "                         OpMemberDecorate %Output 0 ColMajor\n"
297                                               "                         OpMemberDecorate %Output 0 MatrixStride 16\n";
298         }
299 
300         fragments["extension"] += "OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n";
301         fragments["pre_main"]   = preMain.specialize(shaderSpec);
302         fragments["decoration"] = decoration.specialize(shaderSpec);
303         fragments["testfun"]    = testFun.specialize(shaderSpec);
304 
305         createTestsForAllStages(testParams[paramIdx].name, defaultColors, defaultColors, fragments, resources,
306                                 extensions, privateGroup, features);
307     }
308 }
309 
outputTest(Context & context,ShaderParams params)310 tcu::TestStatus outputTest(Context &context, ShaderParams params)
311 {
312     return runAndVerifyDefaultPipeline(context, params.context);
313 }
314 
addShaderCodeOutput(vk::SourceCollections & dst,ShaderParams params)315 void addShaderCodeOutput(vk::SourceCollections &dst, ShaderParams params)
316 {
317 
318     SpirvVersion targetSpirvVersion = params.context.resources.spirvVersion;
319     map<string, string> spec;
320     const uint32_t vulkanVersion = dst.usedVulkanVersion;
321 
322     spec["type"]       = params.type;
323     spec["initSource"] = params.type + "_1";
324 
325     if (params.type == "struct")
326     {
327         // Output structure of matrix, vec4, and four floats all having values of 1.
328         const StringTemplate vertexShader(
329             "                            OpCapability Shader\n"
330             "                       %1 = OpExtInstImport \"GLSL.std.450\"\n"
331             "                            OpMemoryModel Logical GLSL450\n"
332             "                            OpEntryPoint Vertex %main \"main\" %_ %position %vtxColor %color %outData\n"
333             "                            OpSource GLSL 430\n"
334             "                            OpMemberDecorate %gl_PerVertex 0 BuiltIn Position\n"
335             "                            OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize\n"
336             "                            OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance\n"
337             "                            OpDecorate %gl_PerVertex Block\n"
338             "                            OpDecorate %position Location 0\n"
339             "                            OpDecorate %vtxColor Location 1\n"
340             "                            OpDecorate %color Location 1\n"
341             "                            OpDecorate %outData Location 2\n"
342             "                            OpMemberDecorate %Data 0 ColMajor\n"
343             "                            OpMemberDecorate %Data 0 Offset 0\n"
344             "                            OpMemberDecorate %Data 0 MatrixStride 16\n"
345             "                            OpMemberDecorate %Data 1 Offset 32\n"
346             "                            OpMemberDecorate %Data 2 Offset 48\n"
347             "                            OpMemberDecorate %Data 3 Offset 52\n"
348             "                            OpMemberDecorate %Data 4 Offset 56\n"
349             "                            OpMemberDecorate %Data 5 Offset 60\n"
350             "                            OpMemberDecorate %DataOutput 0 Offset 0\n"
351             "                    %void = OpTypeVoid\n"
352             "                %voidFunc = OpTypeFunction %void\n"
353             "                   %float = OpTypeFloat 32\n"
354             "                 %v4float = OpTypeVector %float 4\n"
355             "                    %uint = OpTypeInt 32 0\n"
356             "                  %uint_1 = OpConstant %uint 1\n"
357             "       %_arr_float_uint_1 = OpTypeArray %float %uint_1\n"
358             "            %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1\n"
359             "%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex\n"
360             "                       %_ = OpVariable %_ptr_Output_gl_PerVertex Output\n"
361             "                     %int = OpTypeInt 32 1\n"
362             "                   %int_0 = OpConstant %int 0\n"
363             "      %_ptr_Input_v4float = OpTypePointer Input %v4float\n"
364             "                %position = OpVariable %_ptr_Input_v4float Input\n"
365             "     %_ptr_Output_v4float = OpTypePointer Output %v4float\n"
366             "                %vtxColor = OpVariable %_ptr_Output_v4float Output\n"
367             "                   %color = OpVariable %_ptr_Input_v4float Input\n"
368             "             %mat2v4float = OpTypeMatrix %v4float 2\n"
369             "                    %Data = OpTypeStruct %mat2v4float %v4float %float %float %float %float\n"
370             "              %DataOutput = OpTypeStruct %Data\n"
371             "  %_ptr_Output_DataOutput = OpTypePointer Output %DataOutput\n"
372             "                 %float_1 = OpConstant %float 1\n"
373             "                  %vec4_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n"
374             "                %matrix_1 = OpConstantComposite %mat2v4float %vec4_1 %vec4_1\n"
375             " %_ptr_Output_mat2v4float = OpTypePointer Output %mat2v4float\n"
376             "       %_ptr_Output_float = OpTypePointer Output %float\n"
377             "                  %data_1 = OpConstantComposite %Data %matrix_1 %vec4_1 %float_1 %float_1 %float_1 "
378             "%float_1\n"
379             "                %struct_1 = OpConstantComposite %DataOutput %data_1\n"
380             "     %_ptr_struct_private = OpTypePointer Private %DataOutput\n"
381             "         %struct_global_1 = OpVariable %_ptr_struct_private Private %struct_1\n"
382             "                 %outData = OpVariable %_ptr_Output_DataOutput Output %${initSource}\n"
383             "                    %main = OpFunction %void None %voidFunc\n"
384             "                   %entry = OpLabel\n"
385             "                 %posData = OpLoad %v4float %position\n"
386             "                  %posPtr = OpAccessChain %_ptr_Output_v4float %_ %int_0\n"
387             "                            OpStore %posPtr %posData\n"
388             "               %colorData = OpLoad %v4float %color\n"
389             "                            OpStore %vtxColor %colorData\n"
390             "                            OpReturn\n"
391             "                            OpFunctionEnd\n");
392 
393         // Pass the incoming input struct into buffer.
394         const string fragmentShader =
395             "                            OpCapability Shader\n"
396             "                            OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
397             "                       %1 = OpExtInstImport \"GLSL.std.450\"\n"
398             "                            OpMemoryModel Logical GLSL450\n"
399             "                            OpEntryPoint Fragment %main \"main\" %fragColor %vtxColor %inData\n"
400             "                            OpExecutionMode %main OriginUpperLeft\n"
401             "                            OpSource GLSL 430\n"
402             "                            OpDecorate %fragColor Location 0\n"
403             "                            OpDecorate %vtxColor Location 1\n"
404             "                            OpMemberDecorate %Data 0 ColMajor\n"
405             "                            OpMemberDecorate %Data 0 Offset 0\n"
406             "                            OpMemberDecorate %Data 0 MatrixStride 16\n"
407             "                            OpMemberDecorate %Data 1 Offset 32\n"
408             "                            OpMemberDecorate %Data 2 Offset 48\n"
409             "                            OpMemberDecorate %Data 3 Offset 52\n"
410             "                            OpMemberDecorate %Data 4 Offset 56\n"
411             "                            OpMemberDecorate %Data 5 Offset 60\n"
412             "                            OpMemberDecorate %Output 0 Offset 0\n"
413             "                            OpDecorate %Output Block\n"
414             "                            OpDecorate %dataOutput DescriptorSet 0\n"
415             "                            OpDecorate %dataOutput Binding 0\n"
416             "                            OpDecorate %inData Location 2\n"
417             "                    %void = OpTypeVoid\n"
418             "                %voidFunc = OpTypeFunction %void\n"
419             "                   %float = OpTypeFloat 32\n"
420             "                 %v4float = OpTypeVector %float 4\n"
421             "     %_ptr_Output_v4float = OpTypePointer Output %v4float\n"
422             "               %fragColor = OpVariable %_ptr_Output_v4float Output\n"
423             "      %_ptr_Input_v4float = OpTypePointer Input %v4float\n"
424             "                %vtxColor = OpVariable %_ptr_Input_v4float Input\n"
425             "             %mat2v4float = OpTypeMatrix %v4float 2\n"
426             "                    %Data = OpTypeStruct %mat2v4float %v4float %float %float %float %float\n"
427             "                  %Output = OpTypeStruct %Data\n"
428             "             %_ptr_Output = OpTypePointer StorageBuffer %Output\n"
429             "              %dataOutput = OpVariable %_ptr_Output StorageBuffer\n"
430             "                     %int = OpTypeInt 32 1\n"
431             "                   %int_0 = OpConstant %int 0\n"
432             "               %DataInput = OpTypeStruct %Data\n"
433             "    %_ptr_Input_DataInput = OpTypePointer Input %DataInput\n"
434             "                  %inData = OpVariable %_ptr_Input_DataInput Input\n"
435             "         %_ptr_Input_Data = OpTypePointer Input %Data\n"
436             "               %_ptr_Data = OpTypePointer StorageBuffer %Data\n"
437             "                    %main = OpFunction %void None %voidFunc\n"
438             "                   %entry = OpLabel\n"
439             "               %colorData = OpLoad %v4float %vtxColor\n"
440             "                            OpStore %fragColor %colorData\n"
441             "            %inputDataPtr = OpAccessChain %_ptr_Input_Data %inData %int_0\n"
442             "               %inputData = OpLoad %Data %inputDataPtr\n"
443             "           %outputDataPtr = OpAccessChain %_ptr_Data %dataOutput %int_0\n"
444             "                            OpStore %outputDataPtr %inputData\n"
445             "                            OpReturn\n"
446             "                            OpFunctionEnd\n";
447 
448         dst.spirvAsmSources.add("vert", DE_NULL)
449             << vertexShader.specialize(spec) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
450         dst.spirvAsmSources.add("frag", DE_NULL)
451             << fragmentShader << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
452     }
453     else
454     {
455         // Needed for preventing duplicate pointer declarations.
456         if (params.type == "v4f32")
457         {
458             spec["vec4ptrDeclOutput"] = "";
459             spec["vec4ptrOutput"]     = "outputPtr";
460             spec["vec4ptrDeclInput"]  = "";
461             spec["vec4ptrInput"]      = "inputPtr";
462         }
463         else
464         {
465             spec["vec4ptrDeclOutput"] = "     %_ptr_Output_v4f32 = OpTypePointer Output %v4f32\n";
466             spec["vec4ptrOutput"]     = "_ptr_Output_v4f32";
467             spec["vec4ptrDeclInput"]  = "     %_ptr_Input_v4f32 = OpTypePointer Input %v4f32\n";
468             spec["vec4ptrInput"]      = "_ptr_Input_v4f32";
469         }
470 
471         const string types = "                     %u32 = OpTypeInt 32 0\n"
472                              "                     %f32 = OpTypeFloat 32\n"
473                              "                   %v4f32 = OpTypeVector %f32 4\n"
474                              "                  %matrix = OpTypeMatrix %v4f32 2\n"
475                              "                 %c_u32_0 = OpConstant %u32 0\n"
476                              "                 %c_u32_8 = OpConstant %u32 8\n"
477                              "              %floatArray = OpTypeArray %f32 %c_u32_8\n";
478 
479         if (params.type == "matrix")
480         {
481             spec["extraDecorations"] = "                       OpMemberDecorate %Output 0 ColMajor\n"
482                                        "                       OpMemberDecorate %Output 0 MatrixStride 16\n";
483         }
484 
485         // Output selected data type with all components having value one.
486         const StringTemplate vertexShader(
487             string("                            OpCapability Shader\n"
488                    "                       %1 = OpExtInstImport \"GLSL.std.450\"\n"
489                    "                            OpMemoryModel Logical GLSL450\n"
490                    "                            OpEntryPoint Vertex %main \"main\" %_ %position %vtxColor %color "
491                    "%outData\n"
492                    "                            OpSource GLSL 430\n"
493                    "                            OpMemberDecorate %gl_PerVertex 0 BuiltIn Position\n"
494                    "                            OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize\n"
495                    "                            OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance\n"
496                    "                            OpDecorate %gl_PerVertex Block\n"
497                    "                            OpDecorate %position Location 0\n"
498                    "                            OpDecorate %vtxColor Location 1\n"
499                    "                            OpDecorate %color Location 1\n"
500                    "                            OpDecorate %outData Location 2\n"
501                    "                            OpDecorate %floatArray ArrayStride 4\n"
502                    "                    %void = OpTypeVoid\n"
503                    "                       %3 = OpTypeFunction %void\n") +
504             types +
505             string("                   %f32_1 = OpConstant %f32 1\n"
506                    "        %_ptr_f32_private = OpTypePointer Private %f32\n"
507                    "            %f32_global_1 = OpVariable %_ptr_f32_private Private %f32_1\n"
508                    "                 %v4f32_1 = OpConstantComposite %v4f32 %f32_1 %f32_1 %f32_1 %f32_1\n"
509                    "      %_ptr_v4f32_private = OpTypePointer Private %v4f32\n"
510                    "          %v4f32_global_1 = OpVariable %_ptr_v4f32_private Private %v4f32_1\n"
511                    "                %matrix_1 = OpConstantComposite %matrix %v4f32_1 %v4f32_1\n"
512                    "     %_ptr_matrix_private = OpTypePointer Private %matrix\n"
513                    "         %matrix_global_1 = OpVariable %_ptr_matrix_private Private %matrix_1\n"
514                    "            %floatArray_1 = OpConstantComposite %floatArray %f32_1 %f32_1 %f32_1 %f32_1 %f32_1 "
515                    "%f32_1 %f32_1 %f32_1\n"
516                    " %_ptr_floatArray_private = OpTypePointer Private %floatArray\n"
517                    "     %floatArray_global_1 = OpVariable %_ptr_floatArray_private Private %floatArray_1\n"
518                    "                 %c_u32_1 = OpConstant %u32 1\n"
519                    "          %_arr_f32_u32_1 = OpTypeArray %f32 %c_u32_1\n"
520                    "            %gl_PerVertex = OpTypeStruct %v4f32 %f32 %_arr_f32_u32_1\n"
521                    "%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex\n"
522                    "                       %_ = OpVariable %_ptr_Output_gl_PerVertex Output\n"
523                    "               %outputPtr = OpTypePointer Output %${type}\n"
524                    "                 %outData = OpVariable %outputPtr Output %${initSource}\n"
525                    "        %_ptr_Input_v4f32 = OpTypePointer Input %v4f32\n"
526                    "                %position = OpVariable %_ptr_Input_v4f32 Input\n"
527                    "${vec4ptrDeclOutput}"
528                    "                %vtxColor = OpVariable %${vec4ptrOutput} Output\n"
529                    "                   %color = OpVariable %_ptr_Input_v4f32 Input\n"
530                    "                    %main = OpFunction %void None %3\n"
531                    "                   %entry = OpLabel\n"
532                    "                 %posData = OpLoad %v4f32 %position\n"
533                    "            %posOutputPtr = OpAccessChain %${vec4ptrOutput} %_ %c_u32_0\n"
534                    "                            OpStore %posOutputPtr %posData\n"
535                    "               %colorData = OpLoad %v4f32 %color\n"
536                    "                            OpStore %vtxColor %colorData\n"
537                    "                            OpReturn\n"
538                    "                            OpFunctionEnd\n"));
539 
540         // Pass incoming data into buffer
541         const StringTemplate fragmentShader(
542             string("                       OpCapability Shader\n"
543                    "                       OpExtension \"SPV_KHR_storage_buffer_storage_class\"\n"
544                    "                  %1 = OpExtInstImport \"GLSL.std.450\"\n"
545                    "                       OpMemoryModel Logical GLSL450\n"
546                    "                       OpEntryPoint Fragment %main \"main\" %fragColor %vtxColor %inData\n"
547                    "                       OpExecutionMode %main OriginUpperLeft\n"
548                    "                       OpSource GLSL 430\n"
549                    "                       OpDecorate %fragColor Location 0\n"
550                    "                       OpDecorate %vtxColor Location 1\n"
551                    "                       OpMemberDecorate %Output 0 Offset 0\n"
552                    "                       OpDecorate %Output Block\n"
553                    "                       OpDecorate %dataOutput DescriptorSet 0\n"
554                    "                       OpDecorate %dataOutput Binding 0\n"
555                    "                       OpDecorate %inData Location 2\n"
556                    "                       OpDecorate %floatArray ArrayStride 4\n"
557                    "${extraDecorations:opt}"
558                    "               %void = OpTypeVoid\n"
559                    "                  %3 = OpTypeFunction %void\n") +
560             types +
561             string("           %inputPtr = OpTypePointer Input %${type}\n"
562                    "             %inData = OpVariable %inputPtr Input\n"
563                    "  %_ptr_Output_v4f32 = OpTypePointer Output %v4f32\n"
564                    "          %fragColor = OpVariable %_ptr_Output_v4f32 Output\n"
565                    "${vec4ptrDeclInput}"
566                    "           %vtxColor = OpVariable %${vec4ptrInput} Input\n"
567                    "             %Output = OpTypeStruct %${type}\n"
568                    "        %_ptr_Output = OpTypePointer StorageBuffer %Output\n"
569                    "         %dataOutput = OpVariable %_ptr_Output StorageBuffer\n"
570                    "          %outputPtr = OpTypePointer StorageBuffer %${type}\n"
571                    "               %main = OpFunction %void None %3\n"
572                    "              %entry = OpLabel\n"
573                    "          %colorData = OpLoad %v4f32 %vtxColor\n"
574                    "                       OpStore %fragColor %colorData\n"
575                    "          %inputData = OpLoad %${type} %inData\n"
576                    "      %outputDataPtr = OpAccessChain %outputPtr %dataOutput %c_u32_0\n"
577                    "                       OpStore %outputDataPtr %inputData\n"
578                    "                       OpReturn\n"
579                    "                       OpFunctionEnd\n"));
580 
581         dst.spirvAsmSources.add("vert", DE_NULL)
582             << vertexShader.specialize(spec) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
583         dst.spirvAsmSources.add("frag", DE_NULL)
584             << fragmentShader.specialize(spec) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
585     }
586 }
587 
addGraphicsVariableInitOutputTest(tcu::TestCaseGroup * group)588 void addGraphicsVariableInitOutputTest(tcu::TestCaseGroup *group)
589 {
590     tcu::TestContext &testCtx = group->getTestContext();
591     map<string, string> fragments;
592     RGBA defaultColors[4];
593     // Tests OpVariable initialization in output storage class.
594     tcu::TestCaseGroup *outputGroup = new tcu::TestCaseGroup(testCtx, "output");
595     SpecConstants noSpecConstants;
596     PushConstants noPushConstants;
597     GraphicsInterfaces noInterfaces;
598     vector<string> extensions;
599     map<string, string> noFragments;
600     StageToSpecConstantMap specConstantMap;
601 
602     const ShaderElement pipelineStages[] = {
603         ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
604         ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
605     };
606 
607     specConstantMap[VK_SHADER_STAGE_VERTEX_BIT]   = noSpecConstants;
608     specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = noSpecConstants;
609 
610     getDefaultColors(defaultColors);
611 
612     group->addChild(outputGroup);
613 
614     VulkanFeatures requiredFeatures;
615     requiredFeatures.coreFeatures.fragmentStoresAndAtomics = VK_TRUE;
616     extensions.push_back("VK_KHR_storage_buffer_storage_class");
617 
618     for (int paramIdx = 0; paramIdx < DE_LENGTH_OF_ARRAY(testParams); paramIdx++)
619     {
620         if (testParams[paramIdx].initializationSource == INITIALIZATION_SOURCE_GLOBAL)
621             continue;
622 
623         GraphicsResources resources;
624         vector<float> expectedOutput(testParams[paramIdx].numComponents, 1.0f);
625 
626         resources.outputs.push_back(
627             Resource(BufferSp(new Float32Buffer(expectedOutput)), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER));
628 
629         {
630             const InstanceContext &instanceContext = createInstanceContext(
631                 pipelineStages, defaultColors, defaultColors, noFragments, specConstantMap, noPushConstants, resources,
632                 noInterfaces, extensions, requiredFeatures, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
633                 QP_TEST_RESULT_FAIL, string());
634             const ShaderParams shaderParams = {instanceContext, testParams[paramIdx].type};
635 
636             addFunctionCaseWithPrograms<ShaderParams>(outputGroup, testParams[paramIdx].name.c_str(),
637                                                       addShaderCodeOutput, outputTest, shaderParams);
638         }
639     }
640 }
641 
642 } // namespace
643 
createVariableInitComputeGroup(tcu::TestContext & testCtx)644 tcu::TestCaseGroup *createVariableInitComputeGroup(tcu::TestContext &testCtx)
645 {
646     // Compute tests for OpVariable initialization.
647     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "variable_init"));
648     addComputeVariableInitPrivateTest(group.get());
649 
650     return group.release();
651 }
652 
createVariableInitGraphicsGroup(tcu::TestContext & testCtx)653 tcu::TestCaseGroup *createVariableInitGraphicsGroup(tcu::TestContext &testCtx)
654 {
655     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "variable_init"));
656     addGraphicsVariableInitPrivateTest(group.get());
657     addGraphicsVariableInitOutputTest(group.get());
658 
659     return group.release();
660 }
661 
662 } // namespace SpirVAssembly
663 } // namespace vkt
664