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