xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/pipeline/vktPipelineMaxVaryingsTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Max Varying Tests
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineMaxVaryingsTests.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vktPipelineMakeUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkBarrierUtil.hpp"
39 #include "vktPipelineSpecConstantUtil.hpp"
40 #include "vkImageWithMemory.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuTestLog.hpp"
43 #include "tcuTextureUtil.hpp"
44 
45 #include <string.h>
46 
47 namespace vkt
48 {
49 namespace pipeline
50 {
51 namespace
52 {
53 using namespace vk;
54 using de::MovePtr;
55 using de::UniquePtr;
56 
57 struct MaxVaryingsParam
58 {
59     PipelineConstructionType pipelineConstructionType;
60     VkShaderStageFlags outputStage;
61     VkShaderStageFlags inputStage;
62     VkShaderStageFlags stageToStressIO;
63 };
64 
65 // Helper functions
getShaderStageName(VkShaderStageFlags stage)66 std::string getShaderStageName(VkShaderStageFlags stage)
67 {
68     switch (stage)
69     {
70     default:
71         DE_FATAL("Unhandled stage!");
72         return "";
73     case VK_SHADER_STAGE_COMPUTE_BIT:
74         return "compute";
75     case VK_SHADER_STAGE_FRAGMENT_BIT:
76         return "fragment";
77     case VK_SHADER_STAGE_VERTEX_BIT:
78         return "vertex";
79     case VK_SHADER_STAGE_GEOMETRY_BIT:
80         return "geometry";
81     case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
82         return "tess_control";
83     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
84         return "tess_eval";
85     }
86 }
87 
generateTestName(struct MaxVaryingsParam param)88 const std::string generateTestName(struct MaxVaryingsParam param)
89 {
90     std::ostringstream result;
91 
92     result << "test_" << getShaderStageName(param.stageToStressIO) << "_io_between_";
93     result << getShaderStageName(param.outputStage) << "_";
94     result << getShaderStageName(param.inputStage);
95     return result.str();
96 }
97 
initPrograms(SourceCollections & programCollection,MaxVaryingsParam param)98 void initPrograms(SourceCollections &programCollection, MaxVaryingsParam param)
99 {
100     const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
101 
102     // Vertex shader. SPIR-V generated from:
103     // #version 450
104     // layout(location = 0) in highp vec4 pos;
105     // layout(constant_id = 0) const int arraySize = 1;
106     // layout(location = 0) out ivec4 outputData[arraySize];
107     // out gl_PerVertex {
108     //    vec4 gl_Position;
109     // };
110     //
111     // void main()
112     // {
113     //     gl_Position = pos;
114     //     int i;
115     //     for (i = 0; i &lt; arraySize; i++)
116     //     {
117     //         outputData[i] = ivec4(i);
118     //     }
119     // }
120     std::ostringstream vertex_out;
121     vertex_out << "OpCapability Shader\n"
122                << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
123                << "OpMemoryModel Logical GLSL450\n"
124                << "OpEntryPoint Vertex %4 \"main\" %10 %14 %32\n"
125                << "OpMemberDecorate %8 0 BuiltIn Position\n"
126                << "OpDecorate %8 Block\n"
127                << "OpDecorate %14 Location 0\n"
128                << "OpDecorate %26 SpecId 0\n"
129                << "OpDecorate %32 Location 0\n"
130                << "%2 = OpTypeVoid\n"
131                << "%3 = OpTypeFunction %2\n"
132                << "%6 = OpTypeFloat 32\n"
133                << "%7 = OpTypeVector %6 4\n"
134                << "%8 = OpTypeStruct %7\n"
135                << "%9 = OpTypePointer Output %8\n"
136                << "%10 = OpVariable %9 Output\n"
137                << "%11 = OpTypeInt 32 1\n"
138                << "%12 = OpConstant %11 0\n"
139                << "%13 = OpTypePointer Input %7\n"
140                << "%14 = OpVariable %13 Input\n"
141                << "%16 = OpTypePointer Output %7\n"
142                << "%18 = OpTypePointer Function %11\n"
143                << "%26 = OpSpecConstant %11 1\n"
144                << "%27 = OpTypeBool\n"
145                << "%29 = OpTypeVector %11 4\n"
146                << "%30 = OpTypeArray %29 %26\n"
147                << "%31 = OpTypePointer Output %30\n"
148                << "%32 = OpVariable %31 Output\n"
149                << "%36 = OpTypePointer Output %29\n"
150                << "%39 = OpConstant %11 1\n"
151                << "%4 = OpFunction %2 None %3\n"
152                << "%5 = OpLabel\n"
153                << "%19 = OpVariable %18 Function\n"
154                << "%15 = OpLoad %7 %14\n"
155                << "%17 = OpAccessChain %16 %10 %12\n"
156                << "OpStore %17 %15\n"
157                << "OpStore %19 %12\n"
158                << "OpBranch %20\n"
159                << "%20 = OpLabel\n"
160                << "OpLoopMerge %22 %23 None\n"
161                << "OpBranch %24\n"
162                << "%24 = OpLabel\n"
163                << "%25 = OpLoad %11 %19\n"
164                << "%28 = OpSLessThan %27 %25 %26\n"
165                << "OpBranchConditional %28 %21 %22\n"
166                << "%21 = OpLabel\n"
167                << "%33 = OpLoad %11 %19\n"
168                << "%34 = OpLoad %11 %19\n"
169                << "%35 = OpCompositeConstruct %29 %34 %34 %34 %34\n"
170                << "%37 = OpAccessChain %36 %32 %33\n"
171                << "OpStore %37 %35\n"
172                << "OpBranch %23\n"
173                << "%23 = OpLabel\n"
174                << "%38 = OpLoad %11 %19\n"
175                << "%40 = OpIAdd %11 %38 %39\n"
176                << "OpStore %19 %40\n"
177                << "OpBranch %20\n"
178                << "%22 = OpLabel\n"
179                << "OpReturn\n"
180                << "OpFunctionEnd\n";
181 
182     // Vertex shader passthrough. SPIR-V generated from:
183     // #version 450
184     // layout(location = 0) in highp vec4 pos;
185     // out gl_PerVertex {
186     //    vec4 gl_Position;
187     // };
188     // void main()
189     // {
190     //     gl_Position = pos;
191     // }
192     std::ostringstream vertex_passthrough;
193     vertex_passthrough << "OpCapability Shader\n"
194                        << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
195                        << "OpMemoryModel Logical GLSL450\n"
196                        << "OpEntryPoint Vertex %4 \"main\" %10 %14\n"
197                        << "OpMemberDecorate %8 0 BuiltIn Position\n"
198                        << "OpDecorate %8 Block\n"
199                        << "OpDecorate %14 Location 0\n"
200                        << "%2 = OpTypeVoid\n"
201                        << "%3 = OpTypeFunction %2\n"
202                        << "%6 = OpTypeFloat 32\n"
203                        << "%7 = OpTypeVector %6 4\n"
204                        << "%8 = OpTypeStruct %7\n"
205                        << "%9 = OpTypePointer Output %8\n"
206                        << "%10 = OpVariable %9 Output\n"
207                        << "%11 = OpTypeInt 32 1\n"
208                        << "%12 = OpConstant %11 0\n"
209                        << "%13 = OpTypePointer Input %7\n"
210                        << "%14 = OpVariable %13 Input\n"
211                        << "%16 = OpTypePointer Output %7\n"
212                        << "%4 = OpFunction %2 None %3\n"
213                        << "%5 = OpLabel\n"
214                        << "%15 = OpLoad %7 %14\n"
215                        << "%17 = OpAccessChain %16 %10 %12\n"
216                        << "OpStore %17 %15\n"
217                        << "OpReturn\n"
218                        << "OpFunctionEnd\n";
219 
220     // Tesselation Control shader. SPIR-V generated from:
221     // #version 450
222     // layout(vertices = 3) out;
223     // in gl_PerVertex
224     // {
225     //   vec4 gl_Position;
226     // } gl_in[];
227     // out gl_PerVertex
228     // {
229     //   vec4 gl_Position;
230     // } gl_out[];
231     // void main(void)
232     // {
233     //     if (gl_InvocationID == 0) {
234     //         gl_TessLevelInner[0] = 1.0;
235     //         gl_TessLevelInner[1] = 1.0;
236     //         gl_TessLevelOuter[0] = 1.0;
237     //         gl_TessLevelOuter[1] = 1.0;
238     //         gl_TessLevelOuter[2] = 1.0;
239     //         gl_TessLevelOuter[3] = 1.0;
240     //     }
241     //     gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
242     // }
243     std::ostringstream tcs_passthrough;
244     tcs_passthrough << "OpCapability Tessellation\n"
245                     << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
246                     << "OpMemoryModel Logical GLSL450\n"
247                     << "OpEntryPoint TessellationControl %4 \"main\" %8 %20 %29 %41 %47\n"
248                     << "OpExecutionMode %4 OutputVertices 3\n"
249                     << "OpDecorate %8 BuiltIn InvocationId\n"
250                     << "OpDecorate %20 Patch\n"
251                     << "OpDecorate %20 BuiltIn TessLevelInner\n"
252                     << "OpDecorate %29 Patch\n"
253                     << "OpDecorate %29 BuiltIn TessLevelOuter\n"
254                     << "OpMemberDecorate %37 0 BuiltIn Position\n"
255                     << "OpDecorate %37 Block\n"
256                     << "OpMemberDecorate %43 0 BuiltIn Position\n"
257                     << "OpDecorate %43 Block\n"
258                     << "%2 = OpTypeVoid\n"
259                     << "%3 = OpTypeFunction %2\n"
260                     << "%6 = OpTypeInt 32 1\n"
261                     << "%7 = OpTypePointer Input %6\n"
262                     << "%8 = OpVariable %7 Input\n"
263                     << "%10 = OpConstant %6 0\n"
264                     << "%11 = OpTypeBool\n"
265                     << "%15 = OpTypeFloat 32\n"
266                     << "%16 = OpTypeInt 32 0\n"
267                     << "%17 = OpConstant %16 2\n"
268                     << "%18 = OpTypeArray %15 %17\n"
269                     << "%19 = OpTypePointer Output %18\n"
270                     << "%20 = OpVariable %19 Output\n"
271                     << "%21 = OpConstant %15 1\n"
272                     << "%22 = OpTypePointer Output %15\n"
273                     << "%24 = OpConstant %6 1\n"
274                     << "%26 = OpConstant %16 4\n"
275                     << "%27 = OpTypeArray %15 %26\n"
276                     << "%28 = OpTypePointer Output %27\n"
277                     << "%29 = OpVariable %28 Output\n"
278                     << "%32 = OpConstant %6 2\n"
279                     << "%34 = OpConstant %6 3\n"
280                     << "%36 = OpTypeVector %15 4\n"
281                     << "%37 = OpTypeStruct %36\n"
282                     << "%38 = OpConstant %16 3\n"
283                     << "%39 = OpTypeArray %37 %38\n"
284                     << "%40 = OpTypePointer Output %39\n"
285                     << "%41 = OpVariable %40 Output\n"
286                     << "%43 = OpTypeStruct %36\n"
287                     << "%44 = OpConstant %16 32\n"
288                     << "%45 = OpTypeArray %43 %44\n"
289                     << "%46 = OpTypePointer Input %45\n"
290                     << "%47 = OpVariable %46 Input\n"
291                     << "%49 = OpTypePointer Input %36\n"
292                     << "%52 = OpTypePointer Output %36\n"
293                     << "%4 = OpFunction %2 None %3\n"
294                     << "%5 = OpLabel\n"
295                     << "%9 = OpLoad %6 %8\n"
296                     << "%12 = OpIEqual %11 %9 %10\n"
297                     << "OpSelectionMerge %14 None\n"
298                     << "OpBranchConditional %12 %13 %14\n"
299                     << "%13 = OpLabel\n"
300                     << "%23 = OpAccessChain %22 %20 %10\n"
301                     << "OpStore %23 %21\n"
302                     << "%25 = OpAccessChain %22 %20 %24\n"
303                     << "OpStore %25 %21\n"
304                     << "%30 = OpAccessChain %22 %29 %10\n"
305                     << "OpStore %30 %21\n"
306                     << "%31 = OpAccessChain %22 %29 %24\n"
307                     << "OpStore %31 %21\n"
308                     << "%33 = OpAccessChain %22 %29 %32\n"
309                     << "OpStore %33 %21\n"
310                     << "%35 = OpAccessChain %22 %29 %34\n"
311                     << "OpStore %35 %21\n"
312                     << "OpBranch %14\n"
313                     << "%14 = OpLabel\n"
314                     << "%42 = OpLoad %6 %8\n"
315                     << "%48 = OpLoad %6 %8\n"
316                     << "%50 = OpAccessChain %49 %47 %48 %10\n"
317                     << "%51 = OpLoad %36 %50\n"
318                     << "%53 = OpAccessChain %52 %41 %42 %10\n"
319                     << "OpStore %53 %51\n"
320                     << "OpReturn\n"
321                     << "OpFunctionEnd\n";
322 
323     // Tessellation Evaluation shader. SPIR-V generated from:
324     // #version 450
325     // layout(triangles, equal_spacing, cw) in;
326     // layout(constant_id = 0) const int arraySize = 1;
327     // layout(location = 0) out ivec4 outputData[arraySize];
328     // in gl_PerVertex {
329     //    vec4 gl_Position;
330     // } gl_in[];
331     // out gl_PerVertex {
332     //    vec4 gl_Position;
333     // };
334     // void main(void)
335     // {
336     //     gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position +
337     //                    gl_TessCoord.y * gl_in[1].gl_Position +
338     //                    gl_TessCoord.z * gl_in[2].gl_Position);
339     //     int j;
340     //     for (j = 0; j &lt; arraySize; j++)
341     //     {
342     //         outputData[j] = ivec4(j);
343     //     }
344     // }
345     std::ostringstream tes_out;
346     tes_out << "OpCapability Tessellation\n"
347             << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
348             << "OpMemoryModel Logical GLSL450\n"
349             << "OpEntryPoint TessellationEvaluation %4 \"main\" %10 %15 %25 %62\n"
350             << "OpExecutionMode %4 Triangles\n"
351             << "OpExecutionMode %4 SpacingEqual\n"
352             << "OpExecutionMode %4 VertexOrderCw\n"
353             << "OpMemberDecorate %8 0 BuiltIn Position\n"
354             << "OpDecorate %8 Block\n"
355             << "OpDecorate %15 BuiltIn TessCoord\n"
356             << "OpMemberDecorate %21 0 BuiltIn Position\n"
357             << "OpDecorate %21 Block\n"
358             << "OpDecorate %56 SpecId 0\n"
359             << "OpDecorate %62 Location 0\n"
360             << "%2 = OpTypeVoid\n"
361             << "%3 = OpTypeFunction %2\n"
362             << "%6 = OpTypeFloat 32\n"
363             << "%7 = OpTypeVector %6 4\n"
364             << "%8 = OpTypeStruct %7\n"
365             << "%9 = OpTypePointer Output %8\n"
366             << "%10 = OpVariable %9 Output\n"
367             << "%11 = OpTypeInt 32 1\n"
368             << "%12 = OpConstant %11 0\n"
369             << "%13 = OpTypeVector %6 3\n"
370             << "%14 = OpTypePointer Input %13\n"
371             << "%15 = OpVariable %14 Input\n"
372             << "%16 = OpTypeInt 32 0\n"
373             << "%17 = OpConstant %16 0\n"
374             << "%18 = OpTypePointer Input %6\n"
375             << "%21 = OpTypeStruct %7\n"
376             << "%22 = OpConstant %16 32\n"
377             << "%23 = OpTypeArray %21 %22\n"
378             << "%24 = OpTypePointer Input %23\n"
379             << "%25 = OpVariable %24 Input\n"
380             << "%26 = OpTypePointer Input %7\n"
381             << "%30 = OpConstant %16 1\n"
382             << "%33 = OpConstant %11 1\n"
383             << "%38 = OpConstant %16 2\n"
384             << "%41 = OpConstant %11 2\n"
385             << "%46 = OpTypePointer Output %7\n"
386             << "%48 = OpTypePointer Function %11\n"
387             << "%56 = OpSpecConstant %11 1\n"
388             << "%57 = OpTypeBool\n"
389             << "%59 = OpTypeVector %11 4\n"
390             << "%60 = OpTypeArray %59 %56\n"
391             << "%61 = OpTypePointer Output %60\n"
392             << "%62 = OpVariable %61 Output\n"
393             << "%66 = OpTypePointer Output %59\n"
394             << "%4 = OpFunction %2 None %3\n"
395             << "%5 = OpLabel\n"
396             << "%49 = OpVariable %48 Function\n"
397             << "%19 = OpAccessChain %18 %15 %17\n"
398             << "%20 = OpLoad %6 %19\n"
399             << "%27 = OpAccessChain %26 %25 %12 %12\n"
400             << "%28 = OpLoad %7 %27\n"
401             << "%29 = OpVectorTimesScalar %7 %28 %20\n"
402             << "%31 = OpAccessChain %18 %15 %30\n"
403             << "%32 = OpLoad %6 %31\n"
404             << "%34 = OpAccessChain %26 %25 %33 %12\n"
405             << "%35 = OpLoad %7 %34\n"
406             << "%36 = OpVectorTimesScalar %7 %35 %32\n"
407             << "%37 = OpFAdd %7 %29 %36\n"
408             << "%39 = OpAccessChain %18 %15 %38\n"
409             << "%40 = OpLoad %6 %39\n"
410             << "%42 = OpAccessChain %26 %25 %41 %12\n"
411             << "%43 = OpLoad %7 %42\n"
412             << "%44 = OpVectorTimesScalar %7 %43 %40\n"
413             << "%45 = OpFAdd %7 %37 %44\n"
414             << "%47 = OpAccessChain %46 %10 %12\n"
415             << "OpStore %47 %45\n"
416             << "OpStore %49 %12\n"
417             << "OpBranch %50\n"
418             << "%50 = OpLabel\n"
419             << "OpLoopMerge %52 %53 None\n"
420             << "OpBranch %54\n"
421             << "%54 = OpLabel\n"
422             << "%55 = OpLoad %11 %49\n"
423             << "%58 = OpSLessThan %57 %55 %56\n"
424             << "OpBranchConditional %58 %51 %52\n"
425             << "%51 = OpLabel\n"
426             << "%63 = OpLoad %11 %49\n"
427             << "%64 = OpLoad %11 %49\n"
428             << "%65 = OpCompositeConstruct %59 %64 %64 %64 %64\n"
429             << "%67 = OpAccessChain %66 %62 %63\n"
430             << "OpStore %67 %65\n"
431             << "OpBranch %53\n"
432             << "%53 = OpLabel\n"
433             << "%68 = OpLoad %11 %49\n"
434             << "%69 = OpIAdd %11 %68 %33\n"
435             << "OpStore %49 %69\n"
436             << "OpBranch %50\n"
437             << "%52 = OpLabel\n"
438             << "OpReturn\n"
439             << "OpFunctionEnd\n";
440 
441     // Geometry shader. SPIR-V generated from:
442     // #version 450
443     // layout (triangles) in;
444     // layout (triangle_strip, max_vertices = 3) out;
445     // layout(constant_id = 0) const int arraySize = 1;
446     // layout(location = 0) out ivec4 outputData[arraySize];
447     // in gl_PerVertex {
448     //    vec4 gl_Position;
449     // } gl_in[];
450     // void main()
451     // {
452     //     int i;
453     //     int j;
454     //     for(i = 0; i &lt; gl_in.length(); i++)
455     //     {
456     //         gl_Position = gl_in[i].gl_Position;
457     //         for (j = 0; j &lt; arraySize; j++)
458     //         {
459     //             outputData[j] = ivec4(j);
460     //         }
461     //         EmitVertex();
462     //     }
463     //     EndPrimitive();
464     // }
465     std::ostringstream geom_out;
466     geom_out << "OpCapability Geometry\n"
467              << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
468              << "OpMemoryModel Logical GLSL450\n"
469              << "OpEntryPoint Geometry %4 \"main\" %26 %31 %50\n"
470              << "OpExecutionMode %4 Triangles\n"
471              << "OpExecutionMode %4 Invocations 1\n"
472              << "OpExecutionMode %4 OutputTriangleStrip\n"
473              << "OpExecutionMode %4 OutputVertices 3\n"
474              << "OpMemberDecorate %24 0 BuiltIn Position\n"
475              << "OpDecorate %24 Block\n"
476              << "OpMemberDecorate %27 0 BuiltIn Position\n"
477              << "OpDecorate %27 Block\n"
478              << "OpDecorate %45 SpecId 0\n"
479              << "OpDecorate %50 Location 0\n"
480              << "%2 = OpTypeVoid\n"
481              << "%3 = OpTypeFunction %2\n"
482              << "%6 = OpTypeInt 32 1\n"
483              << "%7 = OpTypePointer Function %6\n"
484              << "%9 = OpConstant %6 0\n"
485              << "%16 = OpConstant %6 3\n"
486              << "%17 = OpTypeBool\n"
487              << "%19 = OpTypeFloat 32\n"
488              << "%20 = OpTypeVector %19 4\n"
489              << "%21 = OpTypeInt 32 0\n"
490              << "%22 = OpConstant %21 1\n"
491              << "%23 = OpTypeArray %19 %22\n"
492              << "%24 = OpTypeStruct %20\n"
493              << "%25 = OpTypePointer Output %24\n"
494              << "%26 = OpVariable %25 Output\n"
495              << "%27 = OpTypeStruct %20\n"
496              << "%28 = OpConstant %21 3\n"
497              << "%29 = OpTypeArray %27 %28\n"
498              << "%30 = OpTypePointer Input %29\n"
499              << "%31 = OpVariable %30 Input\n"
500              << "%33 = OpTypePointer Input %20\n"
501              << "%36 = OpTypePointer Output %20\n"
502              << "%45 = OpSpecConstant %6 1\n"
503              << "%47 = OpTypeVector %6 4\n"
504              << "%48 = OpTypeArray %47 %45\n"
505              << "%49 = OpTypePointer Output %48\n"
506              << "%50 = OpVariable %49 Output\n"
507              << "%54 = OpTypePointer Output %47\n"
508              << "%57 = OpConstant %6 1\n"
509              << "%4 = OpFunction %2 None %3\n"
510              << "%5 = OpLabel\n"
511              << "%8 = OpVariable %7 Function\n"
512              << "%38 = OpVariable %7 Function\n"
513              << "OpStore %8 %9\n"
514              << "OpBranch %10\n"
515              << "%10 = OpLabel\n"
516              << "OpLoopMerge %12 %13 None\n"
517              << "OpBranch %14\n"
518              << "%14 = OpLabel\n"
519              << "%15 = OpLoad %6 %8\n"
520              << "%18 = OpSLessThan %17 %15 %16\n"
521              << "OpBranchConditional %18 %11 %12\n"
522              << "%11 = OpLabel\n"
523              << "%32 = OpLoad %6 %8\n"
524              << "%34 = OpAccessChain %33 %31 %32 %9\n"
525              << "%35 = OpLoad %20 %34\n"
526              << "%37 = OpAccessChain %36 %26 %9\n"
527              << "OpStore %37 %35\n"
528              << "OpStore %38 %9\n"
529              << "OpBranch %39\n"
530              << "%39 = OpLabel\n"
531              << "OpLoopMerge %41 %42 None\n"
532              << "OpBranch %43\n"
533              << "%43 = OpLabel\n"
534              << "%44 = OpLoad %6 %38\n"
535              << "%46 = OpSLessThan %17 %44 %45\n"
536              << "OpBranchConditional %46 %40 %41\n"
537              << "%40 = OpLabel\n"
538              << "%51 = OpLoad %6 %38\n"
539              << "%52 = OpLoad %6 %38\n"
540              << "%53 = OpCompositeConstruct %47 %52 %52 %52 %52\n"
541              << "%55 = OpAccessChain %54 %50 %51\n"
542              << "OpStore %55 %53\n"
543              << "OpBranch %42\n"
544              << "%42 = OpLabel\n"
545              << "%56 = OpLoad %6 %38\n"
546              << "%58 = OpIAdd %6 %56 %57\n"
547              << "OpStore %38 %58\n"
548              << "OpBranch %39\n"
549              << "%41 = OpLabel\n"
550              << "OpEmitVertex\n"
551              << "OpBranch %13\n"
552              << "%13 = OpLabel\n"
553              << "%59 = OpLoad %6 %8\n"
554              << "%60 = OpIAdd %6 %59 %57\n"
555              << "OpStore %8 %60\n"
556              << "OpBranch %10\n"
557              << "%12 = OpLabel\n"
558              << "OpEndPrimitive\n"
559              << "OpReturn\n"
560              << "OpFunctionEnd\n";
561 
562     // Fragment shader. SPIR-V code generated from:
563     //
564     // #version 450
565     // layout(constant_id = 0) const int arraySize = 1;
566     // layout(location = 0) flat in ivec4 inputData[arraySize];
567     // layout(location = 0) out vec4 color;
568     // void main()
569     // {
570     //    color = vec4(1.0, 0.0, 0.0, 1.0);
571     //    int i;
572     //    bool result = true;
573     //    for (i = 0; i &lt; arraySize; i++)
574     //    {
575     //        if (result &amp;&amp; inputData[i] != ivec4(i))
576     //            result = false;
577     //    }
578     //    if (result)
579     //      color = vec4(0.0, 1.0, 0.0, 1.0);
580     // }
581     std::ostringstream fragment_in;
582     fragment_in << "OpCapability Shader\n"
583                 << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
584                 << "OpMemoryModel Logical GLSL450\n"
585                 << "OpEntryPoint Fragment %4 \"main\" %9 %35\n"
586                 << "OpExecutionMode %4 OriginUpperLeft\n"
587                 << "OpDecorate %9 Location 0\n"
588                 << "OpDecorate %27 SpecId 0\n"
589                 << "OpDecorate %35 Flat\n"
590                 << "OpDecorate %35 Location 0\n"
591                 << "%2 = OpTypeVoid\n"
592                 << "%3 = OpTypeFunction %2\n"
593                 << "%6 = OpTypeFloat 32\n"
594                 << "%7 = OpTypeVector %6 4\n"
595                 << "%8 = OpTypePointer Output %7\n"
596                 << "%9 = OpVariable %8 Output\n"
597                 << "%10 = OpConstant %6 1\n"
598                 << "%11 = OpConstant %6 0\n"
599                 << "%12 = OpConstantComposite %7 %10 %11 %11 %10\n"
600                 << "%13 = OpTypeBool\n"
601                 << "%14 = OpTypePointer Function %13\n"
602                 << "%16 = OpConstantTrue %13\n"
603                 << "%17 = OpTypeInt 32 1\n"
604                 << "%18 = OpTypePointer Function %17\n"
605                 << "%20 = OpConstant %17 0\n"
606                 << "%27 = OpSpecConstant %17 1\n"
607                 << "%32 = OpTypeVector %17 4\n"
608                 << "%33 = OpTypeArray %32 %27\n"
609                 << "%34 = OpTypePointer Input %33\n"
610                 << "%35 = OpVariable %34 Input\n"
611                 << "%37 = OpTypePointer Input %32\n"
612                 << "%42 = OpTypeVector %13 4\n"
613                 << "%48 = OpConstantFalse %13\n"
614                 << "%50 = OpConstant %17 1\n"
615                 << "%55 = OpConstantComposite %7 %11 %10 %11 %10\n"
616                 << "%4 = OpFunction %2 None %3\n"
617                 << "%5 = OpLabel\n"
618                 << "%15 = OpVariable %14 Function\n"
619                 << "%19 = OpVariable %18 Function\n"
620                 << "OpStore %9 %12\n"
621                 << "OpStore %15 %16\n"
622                 << "OpStore %19 %20\n"
623                 << "OpBranch %21\n"
624                 << "%21 = OpLabel\n"
625                 << "OpLoopMerge %23 %24 None\n"
626                 << "OpBranch %25\n"
627                 << "%25 = OpLabel\n"
628                 << "%26 = OpLoad %17 %19\n"
629                 << "%28 = OpSLessThan %13 %26 %27\n"
630                 << "OpBranchConditional %28 %22 %23\n"
631                 << "%22 = OpLabel\n"
632                 << "%29 = OpLoad %13 %15\n"
633                 << "OpSelectionMerge %31 None\n"
634                 << "OpBranchConditional %29 %30 %31\n"
635                 << "%30 = OpLabel\n"
636                 << "%36 = OpLoad %17 %19\n"
637                 << "%38 = OpAccessChain %37 %35 %36\n"
638                 << "%39 = OpLoad %32 %38\n"
639                 << "%40 = OpLoad %17 %19\n"
640                 << "%41 = OpCompositeConstruct %32 %40 %40 %40 %40\n"
641                 << "%43 = OpINotEqual %42 %39 %41\n"
642                 << "%44 = OpAny %13 %43\n"
643                 << "OpBranch %31\n"
644                 << "%31 = OpLabel\n"
645                 << "%45 = OpPhi %13 %29 %22 %44 %30\n"
646                 << "OpSelectionMerge %47 None\n"
647                 << "OpBranchConditional %45 %46 %47\n"
648                 << "%46 = OpLabel\n"
649                 << "OpStore %15 %48\n"
650                 << "OpBranch %47\n"
651                 << "%47 = OpLabel\n"
652                 << "OpBranch %24\n"
653                 << "%24 = OpLabel\n"
654                 << "%49 = OpLoad %17 %19\n"
655                 << "%51 = OpIAdd %17 %49 %50\n"
656                 << "OpStore %19 %51\n"
657                 << "OpBranch %21\n"
658                 << "%23 = OpLabel\n"
659                 << "%52 = OpLoad %13 %15\n"
660                 << "OpSelectionMerge %54 None\n"
661                 << "OpBranchConditional %52 %53 %54\n"
662                 << "%53 = OpLabel\n"
663                 << "OpStore %9 %55\n"
664                 << "OpBranch %54\n"
665                 << "%54 = OpLabel\n"
666                 << "OpReturn\n"
667                 << "OpFunctionEnd\n";
668 
669     if (param.outputStage == VK_SHADER_STAGE_VERTEX_BIT)
670     {
671         programCollection.spirvAsmSources.add("vert") << vertex_out.str().c_str();
672 
673         if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT)
674         {
675             programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str();
676             return;
677         }
678     }
679 
680     programCollection.spirvAsmSources.add("vert") << vertex_passthrough.str().c_str();
681 
682     if (param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
683     {
684         programCollection.spirvAsmSources.add("tcs") << tcs_passthrough.str().c_str();
685         programCollection.spirvAsmSources.add("tes") << tes_out.str().c_str();
686 
687         if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT)
688         {
689             programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str();
690             return;
691         }
692     }
693 
694     if (param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT)
695     {
696         programCollection.spirvAsmSources.add("geom") << geom_out.str().c_str();
697         programCollection.spirvAsmSources.add("frag") << fragment_in.str().c_str();
698         return;
699     }
700 
701     DE_FATAL("Unsupported combination");
702 }
703 
supportedCheck(Context & context,MaxVaryingsParam param)704 void supportedCheck(Context &context, MaxVaryingsParam param)
705 {
706 
707     const vk::InstanceInterface &vki = context.getInstanceInterface();
708     VkPhysicalDeviceFeatures features;
709     vki.getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
710 
711     // Check support for the tessellation and geometry shaders on the device
712     if ((param.inputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
713          param.inputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT ||
714          param.outputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
715          param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) &&
716         !features.tessellationShader)
717     {
718         TCU_THROW(NotSupportedError, "Device does not support tessellation shaders");
719     }
720 
721     if ((param.inputStage == VK_SHADER_STAGE_GEOMETRY_BIT || param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT) &&
722         !features.geometryShader)
723     {
724         TCU_THROW(NotSupportedError, "Device does not support geometry shaders");
725     }
726 
727     // Check data sizes, throw unsupported if the case cannot be tested.
728     VkPhysicalDeviceProperties properties;
729     vki.getPhysicalDeviceProperties(context.getPhysicalDevice(), &properties);
730     std::ostringstream error;
731     if (param.stageToStressIO == VK_SHADER_STAGE_VERTEX_BIT)
732     {
733         DE_ASSERT(param.outputStage == VK_SHADER_STAGE_VERTEX_BIT);
734         if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT &&
735             properties.limits.maxFragmentInputComponents < (properties.limits.maxVertexOutputComponents - 4))
736         {
737             error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents
738                   << ") than VS outputs (" << properties.limits.maxVertexOutputComponents << " - 4 built-ins)";
739             TCU_THROW(NotSupportedError, error.str().c_str());
740         }
741     }
742 
743     if (param.stageToStressIO == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
744     {
745         if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT &&
746             properties.limits.maxFragmentInputComponents <
747                 (properties.limits.maxTessellationEvaluationOutputComponents - 4))
748         {
749             error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents
750                   << ") than TES outputs (" << properties.limits.maxTessellationEvaluationOutputComponents
751                   << " - 4 builtins)";
752             TCU_THROW(NotSupportedError, error.str().c_str());
753         }
754     }
755 
756     if (param.stageToStressIO == VK_SHADER_STAGE_GEOMETRY_BIT)
757     {
758         if (param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT &&
759             properties.limits.maxFragmentInputComponents < (properties.limits.maxGeometryOutputComponents - 4))
760         {
761             error << "Device supports smaller number of FS inputs (" << properties.limits.maxFragmentInputComponents
762                   << ") than GS outputs (" << properties.limits.maxGeometryOutputComponents << " - 4 built-ins)";
763             TCU_THROW(NotSupportedError, error.str().c_str());
764         }
765     }
766 
767     if (param.stageToStressIO == VK_SHADER_STAGE_FRAGMENT_BIT)
768     {
769         DE_ASSERT(param.inputStage == VK_SHADER_STAGE_FRAGMENT_BIT);
770 
771         if (param.outputStage == VK_SHADER_STAGE_VERTEX_BIT &&
772             (properties.limits.maxVertexOutputComponents - 4) < properties.limits.maxFragmentInputComponents)
773         {
774             error << "Device supports smaller number of VS outputs (" << properties.limits.maxVertexOutputComponents
775                   << " - 4 built-ins) than FS inputs (" << properties.limits.maxFragmentInputComponents << ")";
776             TCU_THROW(NotSupportedError, error.str().c_str());
777         }
778         if (param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT &&
779             (properties.limits.maxGeometryOutputComponents - 4) < properties.limits.maxFragmentInputComponents)
780         {
781             error << "Device supports smaller number of GS outputs (" << properties.limits.maxGeometryOutputComponents
782                   << " - 4 built-ins) than FS inputs (" << properties.limits.maxFragmentInputComponents << ")";
783             TCU_THROW(NotSupportedError, error.str().c_str());
784         }
785         if (param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT &&
786             (properties.limits.maxTessellationEvaluationOutputComponents - 4) <
787                 properties.limits.maxFragmentInputComponents)
788         {
789             error << "Device supports smaller number of TES outputs ("
790                   << properties.limits.maxTessellationEvaluationOutputComponents << " - 4 built-ins) than FS inputs ("
791                   << properties.limits.maxFragmentInputComponents << ")";
792             TCU_THROW(NotSupportedError, error.str().c_str());
793         }
794     }
795 
796     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
797                                           param.pipelineConstructionType);
798 }
799 
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)800 VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const VkFormat format, const VkImageUsageFlags usage)
801 {
802     const VkImageCreateInfo imageInfo = {
803         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
804         DE_NULL,                             // const void* pNext;
805         (VkImageCreateFlags)0,               // VkImageCreateFlags flags;
806         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
807         format,                              // VkFormat format;
808         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
809         1u,                                  // uint32_t mipLevels;
810         1u,                                  // uint32_t arrayLayers;
811         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
812         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
813         usage,                               // VkImageUsageFlags usage;
814         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
815         0u,                                  // uint32_t queueFamilyIndexCount;
816         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
817         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
818     };
819     return imageInfo;
820 }
821 
makeBuffer(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize bufferSize,const VkBufferUsageFlags usage)822 Move<VkBuffer> makeBuffer(const DeviceInterface &vk, const VkDevice device, const VkDeviceSize bufferSize,
823                           const VkBufferUsageFlags usage)
824 {
825     const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, usage);
826     return createBuffer(vk, device, &bufferCreateInfo);
827 }
828 
recordImageBarrier(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkImage image,const VkImageAspectFlags aspect,const VkPipelineStageFlags srcStageMask,const VkPipelineStageFlags dstStageMask,const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask,const VkImageLayout oldLayout,const VkImageLayout newLayout,const VkSampleLocationsInfoEXT * pSampleLocationsInfo=DE_NULL)829 void recordImageBarrier(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const VkImage image,
830                         const VkImageAspectFlags aspect, const VkPipelineStageFlags srcStageMask,
831                         const VkPipelineStageFlags dstStageMask, const VkAccessFlags srcAccessMask,
832                         const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout,
833                         const VkSampleLocationsInfoEXT *pSampleLocationsInfo = DE_NULL)
834 {
835     const VkImageMemoryBarrier barrier = {
836         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,            // VkStructureType sType;
837         pSampleLocationsInfo,                              // const void* pNext;
838         srcAccessMask,                                     // VkAccessFlags srcAccessMask;
839         dstAccessMask,                                     // VkAccessFlags dstAccessMask;
840         oldLayout,                                         // VkImageLayout oldLayout;
841         newLayout,                                         // VkImageLayout newLayout;
842         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t srcQueueFamilyIndex;
843         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t dstQueueFamilyIndex;
844         image,                                             // VkImage image;
845         makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
846     };
847 
848     vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u,
849                           &barrier);
850 }
851 
recordCopyImageToBuffer(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const tcu::IVec2 & imageSize,const VkImage srcImage,const VkBuffer dstBuffer)852 void recordCopyImageToBuffer(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const tcu::IVec2 &imageSize,
853                              const VkImage srcImage, const VkBuffer dstBuffer)
854 {
855     // Resolve image -> host buffer
856     {
857         const VkBufferImageCopy region = {
858             0ull, // VkDeviceSize bufferOffset;
859             0u,   // uint32_t bufferRowLength;
860             0u,   // uint32_t bufferImageHeight;
861             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
862                                        1u),                 // VkImageSubresourceLayers imageSubresource;
863             makeOffset3D(0, 0, 0),                          // VkOffset3D imageOffset;
864             makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent;
865         };
866 
867         vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, &region);
868     }
869     // Buffer write barrier
870     {
871         const VkBufferMemoryBarrier barrier = {
872             VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
873             DE_NULL,                                 // const void* pNext;
874             VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags srcAccessMask;
875             VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags dstAccessMask;
876             VK_QUEUE_FAMILY_IGNORED,                 // uint32_t srcQueueFamilyIndex;
877             VK_QUEUE_FAMILY_IGNORED,                 // uint32_t dstQueueFamilyIndex;
878             dstBuffer,                               // VkBuffer buffer;
879             0ull,                                    // VkDeviceSize offset;
880             VK_WHOLE_SIZE,                           // VkDeviceSize size;
881         };
882 
883         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
884                               (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
885     }
886 }
887 
createBufferAndBindMemory(Context & context,VkDeviceSize size,VkBufferUsageFlags usage,de::MovePtr<Allocation> * pAlloc)888 Move<VkBuffer> createBufferAndBindMemory(Context &context, VkDeviceSize size, VkBufferUsageFlags usage,
889                                          de::MovePtr<Allocation> *pAlloc)
890 {
891     const DeviceInterface &vk       = context.getDeviceInterface();
892     const VkDevice vkDevice         = context.getDevice();
893     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
894 
895     const VkBufferCreateInfo vertexBufferParams = {
896         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
897         DE_NULL,                              // const void* pNext;
898         0u,                                   // VkBufferCreateFlags flags;
899         size,                                 // VkDeviceSize size;
900         usage,                                // VkBufferUsageFlags usage;
901         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
902         1u,                                   // uint32_t queueFamilyCount;
903         &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
904     };
905 
906     Move<VkBuffer> vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
907 
908     *pAlloc = context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer),
909                                                      MemoryRequirement::HostVisible);
910     VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, (*pAlloc)->getMemory(), (*pAlloc)->getOffset()));
911 
912     return vertexBuffer;
913 }
914 
getMaxIOComponents(bool input,VkShaderStageFlags stage,VkPhysicalDeviceProperties properties)915 int32_t getMaxIOComponents(bool input, VkShaderStageFlags stage, VkPhysicalDeviceProperties properties)
916 {
917     int32_t data = 0u;
918     switch (stage)
919     {
920     case VK_SHADER_STAGE_VERTEX_BIT:
921         DE_ASSERT(!input);
922         data = (properties.limits.maxVertexOutputComponents / 4) - 1; // outputData + gl_Position
923         break;
924 
925     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
926         if (input)
927             data = properties.limits.maxTessellationEvaluationInputComponents / 4;
928         else
929             data = (properties.limits.maxTessellationEvaluationOutputComponents / 4) - 1; // outputData + gl_Position
930         break;
931 
932     case VK_SHADER_STAGE_GEOMETRY_BIT:
933         if (input)
934             data = properties.limits.maxGeometryInputComponents / 4;
935         else
936             data = (properties.limits.maxGeometryOutputComponents / 4) - 1; // outputData + gl_Position
937         break;
938 
939     case VK_SHADER_STAGE_FRAGMENT_BIT:
940         DE_ASSERT(input);
941         data = (properties.limits.maxFragmentInputComponents / 4); // inputData
942         break;
943     default:
944         DE_FATAL("Unsupported shader");
945     }
946 
947     return data;
948 }
949 
test(Context & context,const MaxVaryingsParam param)950 tcu::TestStatus test(Context &context, const MaxVaryingsParam param)
951 {
952     const InstanceInterface &vki          = context.getInstanceInterface();
953     const DeviceInterface &vk             = context.getDeviceInterface();
954     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
955     const VkDevice device                 = context.getDevice();
956     const VkQueue queue                   = context.getUniversalQueue();
957     const uint32_t queueFamilyIndex       = context.getUniversalQueueFamilyIndex();
958     Allocator &allocator                  = context.getDefaultAllocator();
959     tcu::TestLog &log                     = context.getTestContext().getLog();
960 
961     // Color attachment
962     const tcu::IVec2 renderSize = tcu::IVec2(32, 32);
963     const VkFormat imageFormat  = VK_FORMAT_R8G8B8A8_UNORM;
964     const ImageWithMemory colorImage(
965         vk, device, allocator,
966         makeImageCreateInfo(renderSize, imageFormat,
967                             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
968         MemoryRequirement::Any);
969     const Unique<VkImageView> colorImageView(
970         makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat,
971                       makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)));
972     const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(imageFormat));
973     Move<VkBuffer> colorBuffer =
974         vkt::pipeline::makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
975     MovePtr<Allocation> colorBufferAlloc =
976         bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible);
977 
978     // Create vertex buffer
979     de::MovePtr<Allocation> vertexBufferMemory;
980     Move<VkBuffer> vertexBuffer = createBufferAndBindMemory(context, sizeof(tcu::Vec4) * 6u,
981                                                             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertexBufferMemory);
982     std::vector<tcu::Vec4> vertices;
983     {
984         vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
985         vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
986         vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
987         vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
988         vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
989         vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
990         // Load vertices into vertex buffer
991         deMemcpy(vertexBufferMemory->getHostPtr(), vertices.data(), vertices.size() * sizeof(tcu::Vec4));
992         flushAlloc(vk, device, *vertexBufferMemory);
993     }
994 
995     // Specialization
996     VkPhysicalDeviceProperties properties;
997     vki.getPhysicalDeviceProperties(context.getPhysicalDevice(), &properties);
998     VkPhysicalDeviceFeatures features;
999     vki.getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
1000 
1001     int32_t data    = 0u;
1002     size_t dataSize = sizeof(data);
1003 
1004     int32_t maxOutput = getMaxIOComponents(false, param.outputStage, properties);
1005     int32_t maxInput  = getMaxIOComponents(true, param.inputStage, properties);
1006 
1007     data = deMin32(maxOutput, maxInput);
1008 
1009     DE_ASSERT(data != 0u);
1010 
1011     log << tcu::TestLog::Message << "Testing " << data * 4 << " input components for stage "
1012         << getShaderStageName(param.stageToStressIO).c_str() << tcu::TestLog::EndMessage;
1013 
1014     VkSpecializationMapEntry mapEntries = {
1015         0u,      // uint32_t constantID;
1016         0u,      // uint32_t offset;
1017         dataSize // size_t size;
1018     };
1019 
1020     VkSpecializationInfo pSpecInfo = {
1021         1u,          // uint32_t mapEntryCount;
1022         &mapEntries, // const VkSpecializationMapEntry* pMapEntries;
1023         dataSize,    // size_t dataSize;
1024         &data        // const void* pData;
1025     };
1026 
1027     // Pipeline
1028 
1029     RenderPassWrapper renderPass(param.pipelineConstructionType, vk, device, imageFormat);
1030     renderPass.createFramebuffer(vk, device, 1u, &colorImage.get(), &colorImageView.get(),
1031                                  static_cast<uint32_t>(renderSize.x()), static_cast<uint32_t>(renderSize.y()));
1032     const PipelineLayoutWrapper pipelineLayout(param.pipelineConstructionType, vk, device);
1033     const Unique<VkCommandPool> cmdPool(
1034         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1035     const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1036 
1037     vk::BinaryCollection &binaryCollection(context.getBinaryCollection());
1038     VkPrimitiveTopology topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
1039     const std::vector<VkViewport> viewport{makeViewport(renderSize)};
1040     const std::vector<VkRect2D> scissor{makeRect2D(renderSize)};
1041 
1042     ShaderWrapper vertShaderModule = ShaderWrapper(vk, device, binaryCollection.get("vert"), 0u);
1043     ShaderWrapper tescShaderModule;
1044     ShaderWrapper teseShaderModule;
1045     ShaderWrapper geomShaderModule;
1046     ShaderWrapper fragShaderModule = ShaderWrapper(vk, device, binaryCollection.get("frag"), 0u);
1047 
1048     if (param.inputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1049         param.outputStage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1050         param.inputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT ||
1051         param.outputStage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
1052     {
1053         tescShaderModule = ShaderWrapper(vk, device, binaryCollection.get("tcs"), 0u);
1054         teseShaderModule = ShaderWrapper(vk, device, binaryCollection.get("tes"), 0u);
1055         topology         = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
1056     }
1057     if (param.inputStage == VK_SHADER_STAGE_GEOMETRY_BIT || param.outputStage == VK_SHADER_STAGE_GEOMETRY_BIT)
1058         geomShaderModule = ShaderWrapper(vk, device, binaryCollection.get("geom"), 0u);
1059 
1060     GraphicsPipelineWrapper graphicsPipeline(vki, vk, physicalDevice, device, context.getDeviceExtensions(),
1061                                              param.pipelineConstructionType);
1062     graphicsPipeline.setDefaultTopology(topology)
1063         .setDefaultRasterizationState()
1064         .setDefaultDepthStencilState()
1065         .setDefaultMultisampleState()
1066         .setDefaultColorBlendState()
1067         .setupVertexInputState()
1068         .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShaderModule, 0u,
1069                                           tescShaderModule, teseShaderModule, geomShaderModule, &pSpecInfo)
1070         .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShaderModule, DE_NULL, DE_NULL, &pSpecInfo)
1071         .setupFragmentOutputState(*renderPass)
1072         .setMonolithicPipelineLayout(pipelineLayout)
1073         .buildPipeline();
1074 
1075     // Draw commands
1076 
1077     const VkRect2D renderArea = makeRect2D(renderSize);
1078     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1079 
1080     beginCommandBuffer(vk, *cmdBuffer);
1081 
1082     {
1083         const VkImageSubresourceRange imageFullSubresourceRange =
1084             makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1085         const VkImageMemoryBarrier barrierColorAttachmentSetInitialLayout =
1086             makeImageMemoryBarrier(0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1087                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorImage, imageFullSubresourceRange);
1088 
1089         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
1090                               0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout);
1091     }
1092 
1093     renderPass.begin(vk, *cmdBuffer, renderArea, clearColor);
1094 
1095     graphicsPipeline.bind(*cmdBuffer);
1096     const VkDeviceSize vertexBufferOffset = 0ull;
1097     vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1098 
1099     // Draw one vertex
1100     vk.cmdDraw(*cmdBuffer, (uint32_t)vertices.size(), 1u, 0u, 0u);
1101     renderPass.end(vk, *cmdBuffer);
1102     // Resolve image -> host buffer
1103     recordImageBarrier(vk, *cmdBuffer, *colorImage,
1104                        VK_IMAGE_ASPECT_COLOR_BIT,                     // VkImageAspectFlags    aspect,
1105                        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
1106                        VK_PIPELINE_STAGE_TRANSFER_BIT,                // VkPipelineStageFlags dstStageMask,
1107                        VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags        srcAccessMask,
1108                        VK_ACCESS_TRANSFER_READ_BIT,                   // VkAccessFlags        dstAccessMask,
1109                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,      // VkImageLayout        oldLayout,
1110                        VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);         // VkImageLayout        newLayout)
1111 
1112     recordCopyImageToBuffer(vk, *cmdBuffer, renderSize, *colorImage, *colorBuffer);
1113     endCommandBuffer(vk, *cmdBuffer);
1114     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1115 
1116     // Verify results
1117     {
1118         invalidateAlloc(vk, device, *colorBufferAlloc);
1119 
1120         const tcu::ConstPixelBufferAccess resultImage(mapVkFormat(imageFormat), renderSize.x(), renderSize.y(), 1u,
1121                                                       colorBufferAlloc->getHostPtr());
1122         tcu::TextureLevel referenceImage(mapVkFormat(imageFormat), renderSize.x(), renderSize.y());
1123         tcu::clear(referenceImage.getAccess(), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
1124 
1125         if (!tcu::floatThresholdCompare(log, "Compare", "Result comparison", referenceImage.getAccess(), resultImage,
1126                                         tcu::Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
1127             TCU_FAIL("Rendered image is not correct");
1128     }
1129     return tcu::TestStatus::pass("OK");
1130 }
1131 } // namespace
1132 
createMaxVaryingsTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)1133 tcu::TestCaseGroup *createMaxVaryingsTests(tcu::TestContext &testCtx, PipelineConstructionType pipelineConstructionType)
1134 {
1135     std::vector<MaxVaryingsParam> tests{
1136         {pipelineConstructionType, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1137          VK_SHADER_STAGE_VERTEX_BIT}, // Test max vertex outputs: VS-FS
1138         {pipelineConstructionType, VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1139          VK_SHADER_STAGE_FRAGMENT_BIT}, // Test max FS inputs: VS-FS
1140         {pipelineConstructionType, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1141          VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT}, // Test max tess evaluation outputs: VS-TCS-TES-FS
1142         {pipelineConstructionType, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1143          VK_SHADER_STAGE_FRAGMENT_BIT}, // Test fragment inputs: VS-TCS-TES-FS
1144         {pipelineConstructionType, VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1145          VK_SHADER_STAGE_GEOMETRY_BIT}, // Test geometry outputs: VS-GS-FS
1146         {pipelineConstructionType, VK_SHADER_STAGE_GEOMETRY_BIT, VK_SHADER_STAGE_FRAGMENT_BIT,
1147          VK_SHADER_STAGE_FRAGMENT_BIT}, // Test fragment inputs: VS-GS-FS
1148     };
1149 
1150     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "max_varyings"));
1151 
1152     for (const auto &testParams : tests)
1153     {
1154         addFunctionCaseWithPrograms(group.get(), generateTestName(testParams), supportedCheck, initPrograms, test,
1155                                     testParams);
1156     }
1157 
1158     return group.release();
1159 }
1160 
1161 } // namespace pipeline
1162 } // namespace vkt
1163