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 < 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 < 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 < gl_in.length(); i++)
455 // {
456 // gl_Position = gl_in[i].gl_Position;
457 // for (j = 0; j < 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 < arraySize; i++)
574 // {
575 // if (result && 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, ®ion);
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