1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tessellation Shader Input/Output Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationShaderInputOutputTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuImageIO.hpp"
31 #include "tcuTexture.hpp"
32 #include "tcuImageCompare.hpp"
33 
34 #include "vkDefs.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkStrUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "vkBufferWithMemory.hpp"
44 #include "vkImageWithMemory.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deStringUtil.hpp"
48 
49 #include <string>
50 #include <vector>
51 
52 namespace vkt
53 {
54 namespace tessellation
55 {
56 
57 using namespace vk;
58 
59 namespace
60 {
61 
62 enum Constants
63 {
64     RENDER_SIZE = 256,
65 };
66 
67 //! Generic test code used by all test cases.
runTest(Context & context,const int numPrimitives,const int inPatchSize,const int outPatchSize,const VkFormat vertexFormat,const void * vertexData,const VkDeviceSize vertexDataSizeBytes,const tcu::ConstPixelBufferAccess & referenceImageAccess)68 tcu::TestStatus runTest(Context &context, const int numPrimitives, const int inPatchSize, const int outPatchSize,
69                         const VkFormat vertexFormat, const void *vertexData, const VkDeviceSize vertexDataSizeBytes,
70                         const tcu::ConstPixelBufferAccess &referenceImageAccess)
71 {
72     requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
73 
74     const DeviceInterface &vk       = context.getDeviceInterface();
75     const VkDevice device           = context.getDevice();
76     const VkQueue queue             = context.getUniversalQueue();
77     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
78     Allocator &allocator            = context.getDefaultAllocator();
79 
80     // Vertex input: may be just some abstract numbers
81 
82     const BufferWithMemory vertexBuffer(vk, device, allocator,
83                                         makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
84                                         MemoryRequirement::HostVisible);
85 
86     {
87         const Allocation &alloc = vertexBuffer.getAllocation();
88 
89         deMemcpy(alloc.getHostPtr(), vertexData, static_cast<std::size_t>(vertexDataSizeBytes));
90         flushAlloc(vk, device, alloc);
91         // No barrier needed, flushed memory is automatically visible
92     }
93 
94     // Color attachment
95 
96     const tcu::IVec2 renderSize = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
97     const VkFormat colorFormat  = VK_FORMAT_R8G8B8A8_UNORM;
98     const VkImageSubresourceRange colorImageSubresourceRange =
99         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
100     const ImageWithMemory colorAttachmentImage(
101         vk, device, allocator,
102         makeImageCreateInfo(renderSize, colorFormat,
103                             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
104         MemoryRequirement::Any);
105 
106     // Color output buffer: image will be copied here for verification
107 
108     const VkDeviceSize colorBufferSizeBytes =
109         renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
110     const BufferWithMemory colorBuffer(vk, device, allocator,
111                                        makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
112                                        MemoryRequirement::HostVisible);
113 
114     // Pipeline
115 
116     const Unique<VkImageView> colorAttachmentView(makeImageView(
117         vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
118     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, colorFormat));
119     const Unique<VkFramebuffer> framebuffer(
120         makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
121     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device));
122     const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
123     const Unique<VkCommandBuffer> cmdBuffer(
124         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
125 
126     const Unique<VkPipeline> pipeline(
127         GraphicsPipelineBuilder()
128             .setRenderSize(renderSize)
129             .setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
130             .setPatchControlPoints(inPatchSize)
131             .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL)
132             .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"),
133                        DE_NULL)
134             .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
135                        context.getBinaryCollection().get("tese"), DE_NULL)
136             .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL)
137             .build(vk, device, *pipelineLayout, *renderPass));
138 
139     {
140         tcu::TestLog &log = context.getTestContext().getLog();
141         log << tcu::TestLog::Message << "Note: input patch size is " << inPatchSize << ", output patch size is "
142             << outPatchSize << tcu::TestLog::EndMessage;
143     }
144 
145     // Draw commands
146 
147     beginCommandBuffer(vk, *cmdBuffer);
148 
149     // Change color attachment image layout
150     {
151         const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
152             (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
153             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorAttachmentImage, colorImageSubresourceRange);
154 
155         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
156                               VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
157                               &colorAttachmentLayoutBarrier);
158     }
159 
160     // Begin render pass
161     {
162         const VkRect2D renderArea = makeRect2D(renderSize);
163         const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
164 
165         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
166     }
167 
168     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
169     {
170         const VkDeviceSize vertexBufferOffset = 0ull;
171         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
172     }
173 
174     // Process enough vertices to make a patch.
175     vk.cmdDraw(*cmdBuffer, numPrimitives * inPatchSize, 1u, 0u, 0u);
176     endRenderPass(vk, *cmdBuffer);
177 
178     // Copy render result to a host-visible buffer
179     copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
180 
181     endCommandBuffer(vk, *cmdBuffer);
182     submitCommandsAndWait(vk, device, queue, *cmdBuffer);
183 
184     {
185         const Allocation &colorBufferAlloc = colorBuffer.getAllocation();
186 
187         invalidateAlloc(vk, device, colorBufferAlloc);
188 
189         // Verify case result
190         const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1,
191                                                             colorBufferAlloc.getHostPtr());
192         tcu::TestLog &log = context.getTestContext().getLog();
193         const bool ok     = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", referenceImageAccess,
194                                               resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT);
195 
196         return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
197     }
198 }
199 
200 //! Resize an image and fill with white color.
initializeWhiteReferenceImage(tcu::TextureLevel & image,const int width,const int height)201 void initializeWhiteReferenceImage(tcu::TextureLevel &image, const int width, const int height)
202 {
203     DE_ASSERT(width > 0 && height > 0);
204 
205     image.setStorage(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), width, height);
206     tcu::PixelBufferAccess access = image.getAccess();
207 
208     const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f);
209 
210     for (int y = 0; y < height; ++y)
211         for (int x = 0; x < width; ++x)
212             access.setPixel(white, x, y);
213 }
214 
215 namespace PatchVertexCount
216 {
217 
218 struct CaseDefinition
219 {
220     int inPatchSize;
221     int outPatchSize;
222     std::string referenceImagePath;
223 };
224 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)225 void initPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
226 {
227     // Vertex shader
228     {
229         std::ostringstream src;
230         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
231             << "\n"
232             << "layout(location = 0) in  highp float in_v_attr;\n"
233             << "layout(location = 0) out highp float in_tc_attr;\n"
234             << "\n"
235             << "void main (void)\n"
236             << "{\n"
237             << "    in_tc_attr = in_v_attr;\n"
238             << "}\n";
239 
240         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
241     }
242 
243     // Tessellation control shader
244     {
245         std::ostringstream src;
246         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
247             << "#extension GL_EXT_tessellation_shader : require\n"
248             << "\n"
249             << "layout(vertices = " << caseDef.outPatchSize << ") out;\n"
250             << "\n"
251             << "layout(location = 0) in  highp float in_tc_attr[];\n"
252             << "layout(location = 0) out highp float in_te_attr[];\n"
253             << "\n"
254             << "void main (void)\n"
255             << "{\n"
256             << "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" << caseDef.inPatchSize << "/"
257             << caseDef.outPatchSize << "];\n"
258             << "\n"
259             << "    gl_TessLevelInner[0] = 5.0;\n"
260             << "    gl_TessLevelInner[1] = 5.0;\n"
261             << "\n"
262             << "    gl_TessLevelOuter[0] = 5.0;\n"
263             << "    gl_TessLevelOuter[1] = 5.0;\n"
264             << "    gl_TessLevelOuter[2] = 5.0;\n"
265             << "    gl_TessLevelOuter[3] = 5.0;\n"
266             << "}\n";
267 
268         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
269     }
270 
271     // Tessellation evaluation shader
272     {
273         std::ostringstream src;
274         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
275             << "#extension GL_EXT_tessellation_shader : require\n"
276             << "\n"
277             << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
278             << "\n"
279             << "layout(location = 0) in  highp   float in_te_attr[];\n"
280             << "layout(location = 0) out mediump vec4  in_f_color;\n"
281             << "\n"
282             << "void main (void)\n"
283             << "{\n"
284             << "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
285             << "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << caseDef.outPatchSize
286             << "-1)))];\n"
287             << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
288             << "    in_f_color = vec4(1.0);\n"
289             << "}\n";
290 
291         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
292     }
293 
294     // Fragment shader
295     {
296         std::ostringstream src;
297         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
298             << "\n"
299             << "layout(location = 0) in  mediump vec4 in_f_color;\n"
300             << "layout(location = 0) out mediump vec4 o_color;\n"
301             << "\n"
302             << "void main (void)\n"
303             << "{\n"
304             << "    o_color = in_f_color;\n"
305             << "}\n";
306 
307         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
308     }
309 }
310 
test(Context & context,const CaseDefinition caseDef)311 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
312 {
313     // Input vertex attribute data
314     std::vector<float> vertexData;
315     vertexData.reserve(caseDef.inPatchSize);
316     for (int i = 0; i < caseDef.inPatchSize; ++i)
317     {
318         const float f = static_cast<float>(i) / static_cast<float>(caseDef.inPatchSize - 1);
319         vertexData.push_back(f * f);
320     }
321     const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
322 
323     // Load reference image
324     tcu::TextureLevel referenceImage;
325     tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str());
326 
327     const int numPrimitives = 1;
328 
329     return runTest(context, numPrimitives, caseDef.inPatchSize, caseDef.outPatchSize, VK_FORMAT_R32_SFLOAT,
330                    &vertexData[0], vertexBufferSize, referenceImage.getAccess());
331 }
332 
333 } // namespace PatchVertexCount
334 
335 namespace PerPatchData
336 {
337 
338 enum CaseType
339 {
340     CASETYPE_PRIMITIVE_ID_TCS,
341     CASETYPE_PRIMITIVE_ID_TES,
342     CASETYPE_PATCH_VERTICES_IN_TCS,
343     CASETYPE_PATCH_VERTICES_IN_TES,
344     CASETYPE_TESS_LEVEL_INNER0_TES,
345     CASETYPE_TESS_LEVEL_INNER1_TES,
346     CASETYPE_TESS_LEVEL_OUTER0_TES,
347     CASETYPE_TESS_LEVEL_OUTER1_TES,
348     CASETYPE_TESS_LEVEL_OUTER2_TES,
349     CASETYPE_TESS_LEVEL_OUTER3_TES,
350 };
351 
352 enum Constants
353 {
354     OUTPUT_PATCH_SIZE = 5,
355     INPUT_PATCH_SIZE  = 10,
356 };
357 
358 struct CaseDefinition
359 {
360     CaseType caseType;
361     std::string caseName;
362     bool usesReferenceImageFromFile;
363     std::string referenceImagePath;
364 };
365 
getNumPrimitives(const CaseType type)366 int getNumPrimitives(const CaseType type)
367 {
368     return (type == CASETYPE_PRIMITIVE_ID_TCS || type == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1);
369 }
370 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)371 void initPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
372 {
373     // Vertex shader
374     {
375         std::ostringstream src;
376         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
377             << "\n"
378             << "layout(location = 0) in  highp float in_v_attr;\n"
379             << "layout(location = 0) out highp float in_tc_attr;\n"
380             << "\n"
381             << "void main (void)\n"
382             << "{\n"
383             << "    in_tc_attr = in_v_attr;\n"
384             << "}\n";
385 
386         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
387     }
388 
389     // Tessellation control shader
390     {
391         std::ostringstream src;
392         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
393             << "#extension GL_EXT_tessellation_shader : require\n"
394             << "\n"
395             << "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n"
396             << "\n"
397             << "layout(location = 0) in  highp float in_tc_attr[];\n"
398             << "layout(location = 0) out highp float in_te_attr[];\n"
399             << "\n"
400             << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ?
401                     "layout(location = 1) patch out mediump int in_te_primitiveIDFromTCS;\n" :
402                 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ?
403                     "layout(location = 1) patch out mediump int in_te_patchVerticesInFromTCS;\n" :
404                     "")
405             << "\n"
406             << "void main (void)\n"
407             << "{\n"
408             << "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
409             << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ?
410                     "    in_te_primitiveIDFromTCS = gl_PrimitiveID;\n" :
411                 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ?
412                     "    in_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n" :
413                     "")
414             << "\n"
415             << "    gl_TessLevelInner[0] = 9.0;\n"
416             << "    gl_TessLevelInner[1] = 8.0;\n"
417             << "\n"
418             << "    gl_TessLevelOuter[0] = 7.0;\n"
419             << "    gl_TessLevelOuter[1] = 6.0;\n"
420             << "    gl_TessLevelOuter[2] = 5.0;\n"
421             << "    gl_TessLevelOuter[3] = 4.0;\n"
422             << "}\n";
423 
424         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
425     }
426 
427     // Tessellation evaluation shader
428     {
429         const float xScale = 1.0f / static_cast<float>(getNumPrimitives(caseDef.caseType));
430 
431         std::ostringstream src;
432         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
433             << "#extension GL_EXT_tessellation_shader : require\n"
434             << "\n"
435             << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
436             << "\n"
437             << "layout(location = 0) in  highp   float in_te_attr[];\n"
438             << "layout(location = 0) out mediump vec4  in_f_color;\n"
439             << "\n"
440             << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ?
441                     "layout(location = 1) patch in mediump int in_te_primitiveIDFromTCS;\n" :
442                 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ?
443                     "layout(location = 1) patch in mediump int in_te_patchVerticesInFromTCS;\n" :
444                     "")
445             << "\n"
446             << "void main (void)\n"
447             << "{\n"
448             << "    highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n"
449             << "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
450             << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
451             << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ?
452                     "    bool ok = in_te_primitiveIDFromTCS == 3;\n" :
453                 caseDef.caseType == CASETYPE_PRIMITIVE_ID_TES ?
454                     "    bool ok = gl_PrimitiveID == 3;\n" :
455                 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ?
456                     "    bool ok = in_te_patchVerticesInFromTCS == " + de::toString(INPUT_PATCH_SIZE) + ";\n" :
457                 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TES ?
458                     "    bool ok = gl_PatchVerticesIn == " + de::toString(OUTPUT_PATCH_SIZE) + ";\n" :
459                 caseDef.caseType == CASETYPE_TESS_LEVEL_INNER0_TES ?
460                     "    bool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n" :
461                 caseDef.caseType == CASETYPE_TESS_LEVEL_INNER1_TES ?
462                     "    bool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n" :
463                 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER0_TES ?
464                     "    bool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n" :
465                 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER1_TES ?
466                     "    bool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n" :
467                 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER2_TES ?
468                     "    bool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n" :
469                 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER3_TES ?
470                     "    bool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n" :
471                     "")
472             << "    in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
473             << "}\n";
474 
475         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
476     }
477 
478     // Fragment shader
479     {
480         std::ostringstream src;
481         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
482             << "\n"
483             << "layout(location = 0) in  mediump vec4 in_f_color;\n"
484             << "layout(location = 0) out mediump vec4 o_color;\n"
485             << "\n"
486             << "void main (void)\n"
487             << "{\n"
488             << "    o_color = in_f_color;\n"
489             << "}\n";
490 
491         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
492     }
493 }
494 
test(Context & context,const CaseDefinition caseDef)495 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
496 {
497     DE_ASSERT(!caseDef.usesReferenceImageFromFile || !caseDef.referenceImagePath.empty());
498 
499     // Input vertex attribute data
500     const int numPrimitives = getNumPrimitives(caseDef.caseType);
501     std::vector<float> vertexData(INPUT_PATCH_SIZE * numPrimitives, 0.0f);
502     const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
503 
504     for (int i = 0; i < numPrimitives; ++i)
505         vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives);
506 
507     tcu::TextureLevel referenceImage;
508     if (caseDef.usesReferenceImageFromFile)
509         tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(),
510                               caseDef.referenceImagePath.c_str());
511     else
512         initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE);
513 
514     return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE, VK_FORMAT_R32_SFLOAT, &vertexData[0],
515                    vertexBufferSize, referenceImage.getAccess());
516 }
517 
518 } // namespace PerPatchData
519 
520 namespace GLPosition
521 {
522 
523 enum CaseType
524 {
525     CASETYPE_VS_TO_TCS = 0,
526     CASETYPE_TCS_TO_TES,
527     CASETYPE_VS_TO_TCS_TO_TES,
528 };
529 
initPrograms(vk::SourceCollections & programCollection,const CaseType caseType)530 void initPrograms(vk::SourceCollections &programCollection, const CaseType caseType)
531 {
532     const bool vsToTCS  = caseType == CASETYPE_VS_TO_TCS || caseType == CASETYPE_VS_TO_TCS_TO_TES;
533     const bool tcsToTES = caseType == CASETYPE_TCS_TO_TES || caseType == CASETYPE_VS_TO_TCS_TO_TES;
534 
535     // Vertex shader
536     {
537         std::ostringstream src;
538         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
539             << "\n"
540             << "layout(location = 0) in  highp vec4 in_v_attr;\n"
541             << (!vsToTCS ? "layout(location = 0) out highp vec4 in_tc_attr;\n" : "") << "\n"
542             << "void main (void)\n"
543             << "{\n"
544             << "    " << (vsToTCS ? "gl_Position" : "in_tc_attr") << " = in_v_attr;\n"
545             << "}\n";
546 
547         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
548     }
549 
550     // Tessellation control shader
551     {
552         std::ostringstream src;
553         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
554             << "#extension GL_EXT_tessellation_shader : require\n"
555             << "\n"
556             << "layout(vertices = 3) out;\n"
557             << "\n"
558             << (!vsToTCS ? "layout(location = 0) in  highp vec4 in_tc_attr[];\n" : "")
559             << (!tcsToTES ? "layout(location = 0) out highp vec4 in_te_attr[];\n" : "") << "\n"
560             << "void main (void)\n"
561             << "{\n"
562             << "    " << (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") << " = "
563             << (vsToTCS ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") << ";\n"
564             << "\n"
565             << "    gl_TessLevelInner[0] = 2.0;\n"
566             << "    gl_TessLevelInner[1] = 3.0;\n"
567             << "\n"
568             << "    gl_TessLevelOuter[0] = 4.0;\n"
569             << "    gl_TessLevelOuter[1] = 5.0;\n"
570             << "    gl_TessLevelOuter[2] = 6.0;\n"
571             << "    gl_TessLevelOuter[3] = 7.0;\n"
572             << "}\n";
573 
574         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
575     }
576 
577     // Tessellation evaluation shader
578     {
579         const std::string tesIn0 = tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
580         const std::string tesIn1 = tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
581         const std::string tesIn2 = tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
582 
583         std::ostringstream src;
584         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
585             << "#extension GL_EXT_tessellation_shader : require\n"
586             << "\n"
587             << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_TRIANGLES) << ") in;\n"
588             << "\n"
589             << (!tcsToTES ? "layout(location = 0) in  highp vec4 in_te_attr[];\n" : "")
590             << "layout(location = 0) out highp vec4 in_f_color;\n"
591             << "\n"
592             << "void main (void)\n"
593             << "{\n"
594             << "    highp vec2 xy = gl_TessCoord.x * " << tesIn0 << ".xy\n"
595             << "                  + gl_TessCoord.y * " << tesIn1 << ".xy\n"
596             << "                  + gl_TessCoord.z * " << tesIn2 << ".xy;\n"
597             << "    gl_Position = vec4(xy, 0.0, 1.0);\n"
598             << "    in_f_color = vec4(" << tesIn0 << ".z + " << tesIn1 << ".w,\n"
599             << "                      " << tesIn2 << ".z + " << tesIn0 << ".w,\n"
600             << "                      " << tesIn1 << ".z + " << tesIn2 << ".w,\n"
601             << "                      1.0);\n"
602             << "}\n";
603 
604         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
605     }
606 
607     // Fragment shader
608     {
609         std::ostringstream src;
610         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
611             << "\n"
612             << "layout(location = 0) in  highp   vec4 in_f_color;\n"
613             << "layout(location = 0) out mediump vec4 o_color;\n"
614             << "\n"
615             << "void main (void)\n"
616             << "{\n"
617             << "    o_color = in_f_color;\n"
618             << "}\n";
619 
620         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
621     }
622 }
623 
test(Context & context,const CaseType caseType)624 tcu::TestStatus test(Context &context, const CaseType caseType)
625 {
626     DE_UNREF(caseType);
627 
628     // Input vertex attribute data
629     static const float vertexData[3 * 4] = {-0.8f, -0.7f, 0.1f, 0.7f, -0.5f, 0.4f, 0.2f, 0.5f, 0.3f, 0.2f, 0.3f, 0.45f};
630 
631     tcu::TextureLevel referenceImage;
632     tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(),
633                           "vulkan/data/tessellation/gl_position_ref.png");
634 
635     const int numPrimitives = 1;
636     const int inPatchSize   = 3;
637     const int outPatchSize  = 3;
638 
639     return runTest(context, numPrimitives, inPatchSize, outPatchSize, VK_FORMAT_R32G32B32A32_SFLOAT, vertexData,
640                    sizeof(vertexData), referenceImage.getAccess());
641 }
642 
643 } // namespace GLPosition
644 
645 namespace Barrier
646 {
647 
648 enum Constants
649 {
650     NUM_VERTICES = 32,
651 };
652 
initPrograms(vk::SourceCollections & programCollection)653 void initPrograms(vk::SourceCollections &programCollection)
654 {
655     // Vertex shader
656     {
657         std::ostringstream src;
658         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
659             << "\n"
660             << "layout(location = 0) in  highp float in_v_attr;\n"
661             << "layout(location = 0) out highp float in_tc_attr;\n"
662             << "\n"
663             << "void main (void)\n"
664             << "{\n"
665             << "    in_tc_attr = in_v_attr;\n"
666             << "}\n";
667 
668         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
669     }
670 
671     // Tessellation control shader
672     {
673         std::ostringstream src;
674         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
675             << "#extension GL_EXT_tessellation_shader : require\n"
676             << "\n"
677             << "layout(vertices = " << NUM_VERTICES << ") out;\n"
678             << "\n"
679             << "layout(location = 0) in  highp float in_tc_attr[];\n"
680             << "layout(location = 0) out highp float in_te_attr[];\n"
681             << "\n"
682             << "layout(location = 1) patch out highp float in_te_patchAttr;\n"
683             << "\n"
684             << "void main (void)\n"
685             << "{\n"
686             << "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
687             << "    in_te_patchAttr = 0.0f;\n"
688             << "\n"
689             << "    barrier();\n"
690             << "\n"
691             << "    if (gl_InvocationID == 5)\n"
692             << "        in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
693             << "\n"
694             << "    barrier();\n"
695             << "\n"
696             << "    highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
697             << "\n"
698             << "    barrier();\n"
699             << "\n"
700             << "    if (gl_InvocationID == " << NUM_VERTICES << "-1)\n"
701             << "        in_te_patchAttr = float(gl_InvocationID);\n"
702             << "\n"
703             << "    barrier();\n"
704             << "\n"
705             << "    in_te_attr[gl_InvocationID] = temp;\n"
706             << "\n"
707             << "    barrier();\n"
708             << "\n"
709             << "    temp = temp + in_te_attr[(gl_InvocationID+1) % " << NUM_VERTICES << "];\n"
710             << "\n"
711             << "    barrier();\n"
712             << "\n"
713             << "    in_te_attr[gl_InvocationID] = 0.25*temp;\n"
714             << "\n"
715             << "    gl_TessLevelInner[0] = 32.0;\n"
716             << "    gl_TessLevelInner[1] = 32.0;\n"
717             << "\n"
718             << "    gl_TessLevelOuter[0] = 32.0;\n"
719             << "    gl_TessLevelOuter[1] = 32.0;\n"
720             << "    gl_TessLevelOuter[2] = 32.0;\n"
721             << "    gl_TessLevelOuter[3] = 32.0;\n"
722             << "}\n";
723 
724         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
725     }
726 
727     // Tessellation evaluation shader
728     {
729         std::ostringstream src;
730         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
731             << "#extension GL_EXT_tessellation_shader : require\n"
732             << "\n"
733             << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
734             << "\n"
735             << "layout(location = 0) in       highp float in_te_attr[];\n"
736             << "layout(location = 1) patch in highp float in_te_patchAttr;\n"
737             << "\n"
738             << "layout(location = 0) out highp float in_f_blue;\n"
739             << "\n"
740             << "void main (void)\n"
741             << "{\n"
742             << "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
743             << "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << NUM_VERTICES
744             << "-1)))];\n"
745             << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
746             << "    in_f_blue = abs(in_te_patchAttr - float(" << NUM_VERTICES << "-1));\n"
747             << "}\n";
748 
749         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
750     }
751 
752     // Fragment shader
753     {
754         std::ostringstream src;
755         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
756             << "\n"
757             << "layout(location = 0) in  highp   float in_f_blue;\n"
758             << "layout(location = 0) out mediump vec4  o_color;\n"
759             << "\n"
760             << "void main (void)\n"
761             << "{\n"
762             << "    o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
763             << "}\n";
764 
765         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
766     }
767 }
768 
test(Context & context)769 tcu::TestStatus test(Context &context)
770 {
771     // Input vertex attribute data
772     std::vector<float> vertexData(NUM_VERTICES);
773     const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
774 
775     for (int i = 0; i < NUM_VERTICES; ++i)
776         vertexData[i] = static_cast<float>(i) / (NUM_VERTICES - 1);
777 
778     tcu::TextureLevel referenceImage;
779     tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(),
780                           "vulkan/data/tessellation/barrier_ref.png");
781 
782     const int numPrimitives = 1;
783     const int inPatchSize   = NUM_VERTICES;
784     const int outPatchSize  = NUM_VERTICES;
785 
786     return runTest(context, numPrimitives, inPatchSize, outPatchSize, VK_FORMAT_R32_SFLOAT, &vertexData[0],
787                    vertexBufferSize, referenceImage.getAccess());
788 }
789 
790 } // namespace Barrier
791 
792 namespace CrossInvocation
793 {
794 
795 enum Constants
796 {
797     OUTPUT_PATCH_SIZE = 3,
798     INPUT_PATCH_SIZE  = 10
799 };
800 
801 enum CaseType
802 {
803     CASETYPE_PER_VERTEX,
804     CASETYPE_PER_PATCH
805 };
806 
807 enum DataType
808 {
809     DATATYPE_INT,
810     DATATYPE_UINT,
811     DATATYPE_FLOAT,
812     DATATYPE_VEC3,
813     DATATYPE_VEC4,
814     DATATYPE_MAT4X3
815 };
816 
817 struct CaseDefinition
818 {
819     CaseType caseType;
820     DataType dataType;
821 };
822 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)823 void initPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
824 {
825     static const std::string typeStr[] = {"int", "uint", "float", "vec3", "vec4", "mat4x3"};
826     const std::string dataType         = typeStr[caseDef.dataType];
827     const int varyingSize[]            = {1, 1, 1, 1, 1, 4};
828 
829     // Vertex shader
830     {
831         std::ostringstream src;
832         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
833             << "\n"
834             << "layout(location = 0) in  highp float in_v_attr;\n"
835             << "layout(location = 0) out highp float in_tc_attr;\n"
836             << "\n"
837             << "void main (void)\n"
838             << "{\n"
839             << "    in_tc_attr = in_v_attr;\n"
840             << "}\n";
841 
842         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
843     }
844 
845     // Tessellation control shader
846     {
847         std::ostringstream src;
848         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
849             << "#extension GL_EXT_tessellation_shader : require\n"
850             << "\n"
851             << "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n"
852             << "\n"
853             << "layout(location = 0) in  highp float in_tc_attr[];\n"
854             << "layout(location = 0) out highp float in_te_attr[];\n"
855             << "\n";
856 
857         if (caseDef.caseType == CASETYPE_PER_VERTEX)
858             src << "layout(location = 1) out mediump " << dataType << " in_te_data0[];\n"
859                 << "layout(location = " << varyingSize[caseDef.dataType] + 1 << ") out mediump " << dataType
860                 << " in_te_data1[];\n";
861         else
862             src << "layout(location = 1) patch out mediump " << dataType << " in_te_data0[" << OUTPUT_PATCH_SIZE
863                 << "];\n"
864                 << "layout(location = " << OUTPUT_PATCH_SIZE * varyingSize[caseDef.dataType] + 1
865                 << ") patch out mediump " << dataType << " in_te_data1[" << OUTPUT_PATCH_SIZE << "];\n";
866 
867         src << "\n"
868             << "void main (void)\n"
869             << "{\n"
870             << "    " << dataType << " d = " << dataType << "(gl_InvocationID);\n"
871             << "    in_te_data0[gl_InvocationID] = d;\n"
872             << "    barrier();\n"
873             << "    in_te_data1[gl_InvocationID] = d + in_te_data0[(gl_InvocationID + 1) % " << OUTPUT_PATCH_SIZE
874             << "];\n"
875             << "\n"
876             << "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
877             << "\n"
878             << "    gl_TessLevelInner[0] = 1.0;\n"
879             << "    gl_TessLevelInner[1] = 1.0;\n"
880             << "\n"
881             << "    gl_TessLevelOuter[0] = 1.0;\n"
882             << "    gl_TessLevelOuter[1] = 1.0;\n"
883             << "    gl_TessLevelOuter[2] = 1.0;\n"
884             << "    gl_TessLevelOuter[3] = 1.0;\n"
885             << "}\n";
886 
887         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
888     }
889 
890     // Tessellation evaluation shader
891     {
892         const float xScale = 1.0f / 8.0f;
893 
894         std::ostringstream src;
895         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
896             << "#extension GL_EXT_tessellation_shader : require\n"
897             << "\n"
898             << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
899             << "\n"
900             << "layout(location = 0) in  highp   float in_te_attr[];\n"
901             << "layout(location = 0) out mediump vec4  in_f_color;\n"
902             << "\n";
903 
904         if (caseDef.caseType == CASETYPE_PER_VERTEX)
905             src << "layout(location = 1) in mediump " << dataType << " in_te_data0[];\n"
906                 << "layout(location = " << varyingSize[caseDef.dataType] + 1 << ") in mediump " << dataType
907                 << " in_te_data1[];\n";
908         else
909             src << "layout(location = 1) patch in mediump " << dataType << " in_te_data0[" << OUTPUT_PATCH_SIZE
910                 << "];\n"
911                 << "layout(location = " << OUTPUT_PATCH_SIZE * varyingSize[caseDef.dataType] + 1
912                 << ") patch in mediump " << dataType << " in_te_data1[" << OUTPUT_PATCH_SIZE << "];\n";
913 
914         src << "\n"
915             << "void main (void)\n"
916             << "{\n"
917             << "    highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n"
918             << "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
919             << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
920             << "    bool ok = true;\n"
921             << "    for (int i = 0; i < " << OUTPUT_PATCH_SIZE << "; i++)\n"
922             << "    {\n"
923             << "         int ref = i + (i + 1) % " << OUTPUT_PATCH_SIZE << ";\n"
924             << "         if (in_te_data1[i] != " << dataType << "(ref)) ok = false;\n"
925             << "    }\n"
926             << "    in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
927             << "}\n";
928 
929         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
930     }
931 
932     // Fragment shader
933     {
934         std::ostringstream src;
935         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
936             << "\n"
937             << "layout(location = 0) in  mediump vec4 in_f_color;\n"
938             << "layout(location = 0) out mediump vec4 o_color;\n"
939             << "\n"
940             << "void main (void)\n"
941             << "{\n"
942             << "    o_color = in_f_color;\n"
943             << "}\n";
944 
945         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
946     }
947 }
948 
test(Context & context,const CaseDefinition caseDef)949 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
950 {
951     DE_UNREF(caseDef);
952     // Input vertex attribute data
953     const int numPrimitives = 8;
954     std::vector<float> vertexData(INPUT_PATCH_SIZE * numPrimitives, 0.0f);
955     const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
956 
957     for (int i = 0; i < numPrimitives; ++i)
958         vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives);
959 
960     tcu::TextureLevel referenceImage;
961     initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE);
962 
963     return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE, VK_FORMAT_R32_SFLOAT, &vertexData[0],
964                    vertexBufferSize, referenceImage.getAccess());
965 }
966 
967 } // namespace CrossInvocation
968 
969 } // namespace
970 
971 //! These tests correspond to dEQP-GLES31.functional.tessellation.shader_input_output.*
createShaderInputOutputTests(tcu::TestContext & testCtx)972 tcu::TestCaseGroup *createShaderInputOutputTests(tcu::TestContext &testCtx)
973 {
974     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_input_output"));
975 
976     // Patch vertex counts
977     {
978         static const struct
979         {
980             int inPatchSize;
981             int outPatchSize;
982         } patchVertexCountCases[] = {{5, 10}, {10, 5}};
983 
984         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
985         {
986             const int inSize  = patchVertexCountCases[caseNdx].inPatchSize;
987             const int outSize = patchVertexCountCases[caseNdx].outPatchSize;
988 
989             const std::string caseName =
990                 "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
991             const PatchVertexCount::CaseDefinition caseDef = {inSize, outSize,
992                                                               "vulkan/data/tessellation/" + caseName + "_ref.png"};
993 
994             // Test input and output patch vertex counts
995             addFunctionCaseWithPrograms(group.get(), caseName, PatchVertexCount::initPrograms, PatchVertexCount::test,
996                                         caseDef);
997         }
998     }
999 
1000     // Per patch data
1001     {
1002         static const PerPatchData::CaseDefinition cases[] = {
1003             // Read gl_PrimitiveID in TCS and pass it as patch output to TES
1004             {PerPatchData::CASETYPE_PRIMITIVE_ID_TCS, "primitive_id_tcs", true,
1005              "vulkan/data/tessellation/primitive_id_tcs_ref.png"},
1006             // Read gl_PrimitiveID in TES
1007             {PerPatchData::CASETYPE_PRIMITIVE_ID_TES, "primitive_id_tes", true,
1008              "vulkan/data/tessellation/primitive_id_tes_ref.png"},
1009             // Read gl_PatchVerticesIn in TCS and pass it as patch output to TES
1010             {PerPatchData::CASETYPE_PATCH_VERTICES_IN_TCS, "patch_vertices_in_tcs", false, ""},
1011             // Read gl_PatchVerticesIn in TES
1012             {PerPatchData::CASETYPE_PATCH_VERTICES_IN_TES, "patch_vertices_in_tes", false, ""},
1013             // Read gl_TessLevelInner[0] in TES
1014             {PerPatchData::CASETYPE_TESS_LEVEL_INNER0_TES, "tess_level_inner_0_tes", false, ""},
1015             // Read gl_TessLevelInner[1] in TES
1016             {PerPatchData::CASETYPE_TESS_LEVEL_INNER1_TES, "tess_level_inner_1_tes", false, ""},
1017             // Read gl_TessLevelOuter[0] in TES
1018             {PerPatchData::CASETYPE_TESS_LEVEL_OUTER0_TES, "tess_level_outer_0_tes", false, ""},
1019             // Read gl_TessLevelOuter[1] in TES
1020             {PerPatchData::CASETYPE_TESS_LEVEL_OUTER1_TES, "tess_level_outer_1_tes", false, ""},
1021             // Read gl_TessLevelOuter[2] in TES
1022             {PerPatchData::CASETYPE_TESS_LEVEL_OUTER2_TES, "tess_level_outer_2_tes", false, ""},
1023             // Read gl_TessLevelOuter[3] in TES
1024             {PerPatchData::CASETYPE_TESS_LEVEL_OUTER3_TES, "tess_level_outer_3_tes", false, ""},
1025         };
1026 
1027         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1028             addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, PerPatchData::initPrograms,
1029                                         PerPatchData::test, cases[caseNdx]);
1030     }
1031 
1032     // gl_Position
1033     {
1034         static const struct
1035         {
1036             GLPosition::CaseType type;
1037             std::string caseName;
1038         } cases[] = {
1039             {GLPosition::CASETYPE_VS_TO_TCS, "gl_position_vs_to_tcs"},
1040             {GLPosition::CASETYPE_TCS_TO_TES, "gl_position_tcs_to_tes"},
1041             {GLPosition::CASETYPE_VS_TO_TCS_TO_TES, "gl_position_vs_to_tcs_to_tes"},
1042         };
1043 
1044         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1045         {
1046             // Pass gl_Position between VS and TCS, or between TCS and TES
1047             addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, GLPosition::initPrograms,
1048                                         GLPosition::test, cases[caseNdx].type);
1049         }
1050     }
1051 
1052     // Barrier
1053     addFunctionCaseWithPrograms(group.get(), "barrier", Barrier::initPrograms, Barrier::test);
1054 
1055     // Cross invocation communication
1056     {
1057         static const struct
1058         {
1059             CrossInvocation::CaseType caseType;
1060             std::string name;
1061         } caseTypes[] = {{CrossInvocation::CASETYPE_PER_VERTEX, "cross_invocation_per_vertex"},
1062                          {CrossInvocation::CASETYPE_PER_PATCH, "cross_invocation_per_patch"}};
1063 
1064         static const struct
1065         {
1066             CrossInvocation::DataType dataType;
1067             std::string name;
1068         } dataTypes[] = {{CrossInvocation::DATATYPE_INT, "int"},     {CrossInvocation::DATATYPE_UINT, "uint"},
1069                          {CrossInvocation::DATATYPE_FLOAT, "float"}, {CrossInvocation::DATATYPE_VEC3, "vec3"},
1070                          {CrossInvocation::DATATYPE_VEC4, "vec4"},   {CrossInvocation::DATATYPE_MAT4X3, "mat4x3"}};
1071 
1072         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(caseTypes); ++caseNdx)
1073             for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(dataTypes); ++dataTypeNdx)
1074             {
1075                 std::string testName                    = caseTypes[caseNdx].name + "_" + dataTypes[dataTypeNdx].name;
1076                 CrossInvocation::CaseDefinition caseDef = {caseTypes[caseNdx].caseType,
1077                                                            dataTypes[dataTypeNdx].dataType};
1078 
1079                 // Write output varyings from multiple invocations.
1080                 addFunctionCaseWithPrograms(group.get(), testName, CrossInvocation::initPrograms, CrossInvocation::test,
1081                                             caseDef);
1082             }
1083     }
1084 
1085     return group.release();
1086 }
1087 
1088 } // namespace tessellation
1089 } // namespace vkt
1090