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 Miscellaneous Draw Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationMiscDrawTests.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 #include <utility>
52 
53 namespace vkt
54 {
55 namespace tessellation
56 {
57 
58 using namespace vk;
59 
60 namespace
61 {
62 
63 struct CaseDefinition
64 {
65     TessPrimitiveType primitiveType;
66     SpacingMode spacingMode;
67     std::string referenceImagePathPrefix; //!< without case suffix and extension (e.g. "_1.png")
68 };
69 
makeCaseDefinition(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const std::string & referenceImagePathPrefix)70 inline CaseDefinition makeCaseDefinition(const TessPrimitiveType primitiveType, const SpacingMode spacingMode,
71                                          const std::string &referenceImagePathPrefix)
72 {
73     CaseDefinition caseDef;
74     caseDef.primitiveType            = primitiveType;
75     caseDef.spacingMode              = spacingMode;
76     caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
77     return caseDef;
78 }
79 
genTessLevelCases(const SpacingMode spacingMode)80 std::vector<TessLevels> genTessLevelCases(const SpacingMode spacingMode)
81 {
82     static const TessLevels tessLevelCases[] = {
83         {{9.0f, 9.0f}, {9.0f, 9.0f, 9.0f, 9.0f}},
84         {{8.0f, 11.0f}, {13.0f, 15.0f, 18.0f, 21.0f}},
85         {{17.0f, 14.0f}, {3.0f, 6.0f, 9.0f, 12.0f}},
86     };
87 
88     std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
89 
90     for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
91     {
92         TessLevels &tessLevels = resultTessLevels[tessLevelCaseNdx];
93 
94         for (int i = 0; i < 2; ++i)
95             tessLevels.inner[i] =
96                 static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
97 
98         for (int i = 0; i < 4; ++i)
99             tessLevels.outer[i] =
100                 static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
101     }
102 
103     return resultTessLevels;
104 }
105 
genVertexPositions(const TessPrimitiveType primitiveType)106 std::vector<tcu::Vec2> genVertexPositions(const TessPrimitiveType primitiveType)
107 {
108     std::vector<tcu::Vec2> positions;
109     positions.reserve(4);
110 
111     if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
112     {
113         positions.push_back(tcu::Vec2(0.8f, 0.6f));
114         positions.push_back(tcu::Vec2(0.0f, -0.786f));
115         positions.push_back(tcu::Vec2(-0.8f, 0.6f));
116     }
117     else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
118     {
119         positions.push_back(tcu::Vec2(-0.8f, -0.8f));
120         positions.push_back(tcu::Vec2(0.8f, -0.8f));
121         positions.push_back(tcu::Vec2(-0.8f, 0.8f));
122         positions.push_back(tcu::Vec2(0.8f, 0.8f));
123     }
124     else
125         DE_ASSERT(false);
126 
127     return positions;
128 }
129 
130 //! Common test function used by all test cases.
runTest(Context & context,const CaseDefinition caseDef)131 tcu::TestStatus runTest(Context &context, const CaseDefinition caseDef)
132 {
133     requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
134 
135     const DeviceInterface &vk       = context.getDeviceInterface();
136     const VkDevice device           = context.getDevice();
137     const VkQueue queue             = context.getUniversalQueue();
138     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
139     Allocator &allocator            = context.getDefaultAllocator();
140 
141     const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
142     const std::vector<tcu::Vec2> vertexData      = genVertexPositions(caseDef.primitiveType);
143     const uint32_t inPatchSize                   = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
144 
145     // Vertex input: positions
146 
147     const VkFormat vertexFormat            = VK_FORMAT_R32G32_SFLOAT;
148     const uint32_t vertexStride            = tcu::getPixelSize(mapVkFormat(vertexFormat));
149     const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
150 
151     const BufferWithMemory vertexBuffer(vk, device, allocator,
152                                         makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
153                                         MemoryRequirement::HostVisible);
154 
155     DE_ASSERT(inPatchSize == vertexData.size());
156     DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
157 
158     {
159         const Allocation &alloc = vertexBuffer.getAllocation();
160 
161         deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
162         flushAlloc(vk, device, alloc);
163         // No barrier needed, flushed memory is automatically visible
164     }
165 
166     // Color attachment
167 
168     const tcu::IVec2 renderSize = tcu::IVec2(256, 256);
169     const VkFormat colorFormat  = VK_FORMAT_R8G8B8A8_UNORM;
170     const VkImageSubresourceRange colorImageSubresourceRange =
171         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
172     const ImageWithMemory colorAttachmentImage(
173         vk, device, allocator,
174         makeImageCreateInfo(renderSize, colorFormat,
175                             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
176         MemoryRequirement::Any);
177 
178     // Color output buffer: image will be copied here for verification
179 
180     const VkDeviceSize colorBufferSizeBytes =
181         renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
182     const BufferWithMemory colorBuffer(vk, device, allocator,
183                                        makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
184                                        MemoryRequirement::HostVisible);
185 
186     // Input buffer: tessellation levels. Data is filled in later.
187 
188     const BufferWithMemory tessLevelsBuffer(
189         vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
190         MemoryRequirement::HostVisible);
191 
192     // Descriptors
193 
194     const Unique<VkDescriptorSetLayout> descriptorSetLayout(
195         DescriptorSetLayoutBuilder()
196             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
197                               VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
198             .build(vk, device));
199 
200     const Unique<VkDescriptorPool> descriptorPool(
201         DescriptorPoolBuilder()
202             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
203             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
204 
205     const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
206 
207     const VkDescriptorBufferInfo tessLevelsBufferInfo =
208         makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
209 
210     DescriptorSetUpdateBuilder()
211         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
212                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
213         .update(vk, device);
214 
215     // Pipeline
216 
217     const Unique<VkImageView> colorAttachmentView(makeImageView(
218         vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
219     const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, colorFormat));
220     const Unique<VkFramebuffer> framebuffer(
221         makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
222     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
223     const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
224     const Unique<VkCommandBuffer> cmdBuffer(
225         allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
226 
227     const Unique<VkPipeline> pipeline(
228         GraphicsPipelineBuilder()
229             .setRenderSize(renderSize)
230             .setVertexInputSingleAttribute(vertexFormat, vertexStride)
231             .setPatchControlPoints(inPatchSize)
232             .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL)
233             .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"),
234                        DE_NULL)
235             .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
236                        context.getBinaryCollection().get("tese"), DE_NULL)
237             .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL)
238             .build(vk, device, *pipelineLayout, *renderPass));
239 
240     // Draw commands
241 
242     uint32_t numPassedCases = 0;
243 
244     for (uint32_t tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
245     {
246         context.getTestContext().getLog()
247             << tcu::TestLog::Message << "Tessellation levels: "
248             << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
249             << tcu::TestLog::EndMessage;
250 
251         // Upload tessellation levels data to the input buffer
252         {
253             const Allocation &alloc            = tessLevelsBuffer.getAllocation();
254             TessLevels *const bufferTessLevels = static_cast<TessLevels *>(alloc.getHostPtr());
255 
256             *bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
257             flushAlloc(vk, device, alloc);
258         }
259 
260         // Reset the command buffer and begin recording.
261         beginCommandBuffer(vk, *cmdBuffer);
262 
263         // Change color attachment image layout
264         {
265             // State is slightly different on the first iteration.
266             const VkImageLayout currentLayout =
267                 (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
268             const VkAccessFlags srcFlags =
269                 (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
270 
271             const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
272                 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
273                 *colorAttachmentImage, colorImageSubresourceRange);
274 
275             vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
276                                   VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
277                                   &colorAttachmentLayoutBarrier);
278         }
279 
280         // Begin render pass
281         {
282             const VkRect2D renderArea = makeRect2D(renderSize);
283             const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
284 
285             beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
286         }
287 
288         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
289         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
290                                  &descriptorSet.get(), 0u, DE_NULL);
291         {
292             const VkDeviceSize vertexBufferOffset = 0ull;
293             vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
294         }
295 
296         // Process enough vertices to make a patch.
297         vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
298         endRenderPass(vk, *cmdBuffer);
299 
300         // Copy render result to a host-visible buffer
301         copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
302 
303         endCommandBuffer(vk, *cmdBuffer);
304         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
305 
306         {
307             const Allocation &colorBufferAlloc = colorBuffer.getAllocation();
308 
309             invalidateAlloc(vk, device, colorBufferAlloc);
310 
311             // Verify case result
312             const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(),
313                                                                 renderSize.y(), 1, colorBufferAlloc.getHostPtr());
314 
315             // Load reference image
316             const std::string referenceImagePath =
317                 caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
318 
319             tcu::TextureLevel referenceImage;
320             tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
321 
322             if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
323                                   referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
324                 ++numPassedCases;
325         }
326     } // tessLevelCaseNdx
327 
328     return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
329 }
330 
getTessLevelsSSBODeclaration(void)331 inline const char *getTessLevelsSSBODeclaration(void)
332 {
333     return "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
334            "    float inner0;\n"
335            "    float inner1;\n"
336            "    float outer0;\n"
337            "    float outer1;\n"
338            "    float outer2;\n"
339            "    float outer3;\n"
340            "} sb_levels;\n";
341 }
342 
343 //! Add vertex, fragment, and tessellation control shaders.
initCommonPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)344 void initCommonPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
345 {
346     DE_ASSERT(!programCollection.glslSources.contains("vert"));
347     DE_ASSERT(!programCollection.glslSources.contains("tesc"));
348     DE_ASSERT(!programCollection.glslSources.contains("frag"));
349 
350     // Vertex shader
351     {
352         std::ostringstream src;
353         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
354             << "\n"
355             << "layout(location = 0) in  highp vec2 in_v_position;\n"
356             << "layout(location = 0) out highp vec2 in_tc_position;\n"
357             << "\n"
358             << "void main (void)\n"
359             << "{\n"
360             << "    in_tc_position = in_v_position;\n"
361             << "}\n";
362 
363         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
364     }
365 
366     // Tessellation control shader
367     {
368         const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
369 
370         std::ostringstream src;
371         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
372             << "#extension GL_EXT_tessellation_shader : require\n"
373             << "\n"
374             << "layout(vertices = " << numVertices << ") out;\n"
375             << "\n"
376             << getTessLevelsSSBODeclaration() << "\n"
377             << "layout(location = 0) in  highp vec2 in_tc_position[];\n"
378             << "layout(location = 0) out highp vec2 in_te_position[];\n"
379             << "\n"
380             << "void main (void)\n"
381             << "{\n"
382             << "    in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
383             << "\n"
384             << "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
385             << "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
386             << "\n"
387             << "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
388             << "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
389             << "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
390             << "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
391             << "}\n";
392 
393         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
394     }
395 
396     // Fragment shader
397     {
398         std::ostringstream src;
399         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
400             << "\n"
401             << "layout(location = 0) in  highp   vec4 in_f_color;\n"
402             << "layout(location = 0) out mediump vec4 o_color;\n"
403             << "\n"
404             << "void main (void)\n"
405             << "{\n"
406             << "    o_color = in_f_color;\n"
407             << "}\n";
408 
409         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
410     }
411 }
412 
initProgramsFillCoverCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)413 void initProgramsFillCoverCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
414 {
415     DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
416 
417     initCommonPrograms(programCollection, caseDef);
418 
419     // Tessellation evaluation shader
420     {
421         std::ostringstream src;
422         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
423             << "#extension GL_EXT_tessellation_shader : require\n"
424             << "\n"
425             << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
426             << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
427             << "\n"
428             << "layout(location = 0) in  highp vec2 in_te_position[];\n"
429             << "layout(location = 0) out highp vec4 in_f_color;\n"
430             << "\n"
431             << "void main (void)\n"
432             << "{\n"
433             << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
434                     "    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
435                     "    highp vec2 corner0 = in_te_position[0];\n"
436                     "    highp vec2 corner1 = in_te_position[1];\n"
437                     "    highp vec2 corner2 = in_te_position[2];\n"
438                     "    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
439                     "    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
440                     "    highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
441                     "    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
442                     "    gl_Position = vec4(pos, 0.0, 1.0);\n" :
443                 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
444                     "    highp vec2 corner0 = in_te_position[0];\n"
445                     "    highp vec2 corner1 = in_te_position[1];\n"
446                     "    highp vec2 corner2 = in_te_position[2];\n"
447                     "    highp vec2 corner3 = in_te_position[3];\n"
448                     "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
449                     "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
450                     "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
451                     "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
452                     "    highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
453                     "    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
454                     "    highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
455                     "    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
456                     "    gl_Position = vec4(pos, 0.0, 1.0);\n" :
457                     "")
458             << "    in_f_color = vec4(1.0);\n"
459             << "}\n";
460 
461         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
462     }
463 }
464 
initProgramsFillNonOverlapCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)465 void initProgramsFillNonOverlapCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
466 {
467     DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
468 
469     initCommonPrograms(programCollection, caseDef);
470 
471     // Tessellation evaluation shader
472     {
473         std::ostringstream src;
474         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
475             << "#extension GL_EXT_tessellation_shader : require\n"
476             << "\n"
477             << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
478             << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
479             << "\n"
480             << getTessLevelsSSBODeclaration() << "\n"
481             << "layout(location = 0) in  highp vec2 in_te_position[];\n"
482             << "layout(location = 0) out highp vec4 in_f_color;\n"
483             << "\n"
484             << "void main (void)\n"
485             << "{\n"
486             << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
487                     "    highp vec2 corner0 = in_te_position[0];\n"
488                     "    highp vec2 corner1 = in_te_position[1];\n"
489                     "    highp vec2 corner2 = in_te_position[2];\n"
490                     "    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
491                     "    gl_Position = vec4(pos, 0.0, 1.0);\n"
492                     "    highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
493                     "    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
494                     "    highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
495                     "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
496                     "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
497                     "               :              vec4(0.0, 0.0, 1.0, 1.0);\n" :
498                 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
499                     "    highp vec2 corner0 = in_te_position[0];\n"
500                     "    highp vec2 corner1 = in_te_position[1];\n"
501                     "    highp vec2 corner2 = in_te_position[2];\n"
502                     "    highp vec2 corner3 = in_te_position[3];\n"
503                     "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
504                     "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
505                     "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
506                     "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
507                     "    gl_Position = vec4(pos, 0.0, 1.0);\n"
508                     "    highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
509                     "    highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
510                     "    highp int phase = min(phaseX, phaseY) % 3;\n"
511                     "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
512                     "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
513                     "               :              vec4(0.0, 0.0, 1.0, 1.0);\n" :
514                     "")
515             << "}\n";
516 
517         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
518     }
519 }
520 
initProgramsIsolinesCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)521 void initProgramsIsolinesCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
522 {
523     DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
524 
525     initCommonPrograms(programCollection, caseDef);
526 
527     // Tessellation evaluation shader
528     {
529         std::ostringstream src;
530         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
531             << "#extension GL_EXT_tessellation_shader : require\n"
532             << "\n"
533             << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
534             << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
535             << "\n"
536             << getTessLevelsSSBODeclaration() << "\n"
537             << "layout(location = 0) in  highp vec2 in_te_position[];\n"
538             << "layout(location = 0) out highp vec4 in_f_color;\n"
539             << "\n"
540             << "void main (void)\n"
541             << "{\n"
542             << "    highp vec2 corner0 = in_te_position[0];\n"
543             << "    highp vec2 corner1 = in_te_position[1];\n"
544             << "    highp vec2 corner2 = in_te_position[2];\n"
545             << "    highp vec2 corner3 = in_te_position[3];\n"
546             << "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
547             << "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
548             << "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
549             << "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
550             << "    pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
551             << "    gl_Position = vec4(pos, 0.0, 1.0);\n"
552             << "    highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
553             << "    highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
554             << "    highp int phase = (phaseX + phaseY) % 3;\n"
555             << "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
556             << "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
557             << "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
558             << "}\n";
559 
560         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
561     }
562 }
563 
getReferenceImagePathPrefix(const std::string & caseName)564 inline std::string getReferenceImagePathPrefix(const std::string &caseName)
565 {
566     return "vulkan/data/tessellation/" + caseName + "_ref";
567 }
568 
569 struct TessStateSwitchParams
570 {
571     const std::pair<TessPrimitiveType, TessPrimitiveType> patchTypes;
572     const std::pair<SpacingMode, SpacingMode> spacing;
573     const std::pair<VkTessellationDomainOrigin, VkTessellationDomainOrigin> domainOrigin;
574     const bool geometryShader;
575 
nonDefaultDomainOriginvkt::tessellation::__anon82f050140111::TessStateSwitchParams576     bool nonDefaultDomainOrigin(void) const
577     {
578         return (domainOrigin.first != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT ||
579                 domainOrigin.second != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT);
580     }
581 };
582 
583 class TessStateSwitchInstance : public vkt::TestInstance
584 {
585 public:
TessStateSwitchInstance(Context & context,const TessStateSwitchParams & params)586     TessStateSwitchInstance(Context &context, const TessStateSwitchParams &params)
587         : vkt::TestInstance(context)
588         , m_params(params)
589     {
590     }
591 
~TessStateSwitchInstance(void)592     virtual ~TessStateSwitchInstance(void)
593     {
594     }
595 
596     tcu::TestStatus iterate(void);
597 
598 protected:
599     const TessStateSwitchParams m_params;
600 };
601 
602 class TessStateSwitchCase : public vkt::TestCase
603 {
604 public:
TessStateSwitchCase(tcu::TestContext & testCtx,const std::string & name,const TessStateSwitchParams & params)605     TessStateSwitchCase(tcu::TestContext &testCtx, const std::string &name, const TessStateSwitchParams &params)
606         : vkt::TestCase(testCtx, name)
607         , m_params(params)
608     {
609     }
610 
~TessStateSwitchCase(void)611     virtual ~TessStateSwitchCase(void)
612     {
613     }
614 
615     void checkSupport(Context &context) const;
616     void initPrograms(vk::SourceCollections &programCollection) const;
createInstance(Context & context) const617     TestInstance *createInstance(Context &context) const
618     {
619         return new TessStateSwitchInstance(context, m_params);
620     }
621 
622 protected:
623     const TessStateSwitchParams m_params;
624 };
625 
checkSupport(Context & context) const626 void TessStateSwitchCase::checkSupport(Context &context) const
627 {
628     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
629 
630     if (m_params.geometryShader)
631         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
632 
633     if (m_params.nonDefaultDomainOrigin())
634         context.requireDeviceFunctionality("VK_KHR_maintenance2");
635 }
636 
initPrograms(vk::SourceCollections & programCollection) const637 void TessStateSwitchCase::initPrograms(vk::SourceCollections &programCollection) const
638 {
639     std::ostringstream vert;
640     vert << "#version 460\n"
641          << "layout (location=0) in vec4 inPos;\n"
642          << "layout (push_constant, std430) uniform PushConstantBlock { vec2 offset; } pc;\n"
643          << "out gl_PerVertex\n"
644          << "{\n"
645          << "  vec4 gl_Position;\n"
646          << "};\n"
647          << "void main() {\n"
648          << "    gl_Position = inPos + vec4(pc.offset, 0.0, 0.0);\n"
649          << "}\n";
650     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
651 
652     if (m_params.geometryShader)
653     {
654         std::ostringstream geom;
655         geom << "#version 460\n"
656              << "layout (triangles) in;\n"
657              << "layout (triangle_strip, max_vertices=3) out;\n"
658              << "in gl_PerVertex\n"
659              << "{\n"
660              << "    vec4 gl_Position;\n"
661              << "} gl_in[3];\n"
662              << "out gl_PerVertex\n"
663              << "{\n"
664              << "    vec4 gl_Position;\n"
665              << "};\n"
666              << "void main() {\n"
667              << "    gl_Position    = gl_in[0].gl_Position; EmitVertex();\n"
668              << "    gl_Position    = gl_in[1].gl_Position; EmitVertex();\n"
669              << "    gl_Position    = gl_in[2].gl_Position; EmitVertex();\n"
670              << "    gl_PrimitiveID = gl_PrimitiveIDIn;     EndPrimitive();\n"
671              << "}\n";
672         programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
673     }
674 
675     const auto even       = (m_params.spacing.second == SPACINGMODE_FRACTIONAL_EVEN);
676     const auto extraLevel = (even ? "1.0" : "0.0");
677 
678     std::ostringstream tesc;
679     tesc << "#version 460\n"
680          << "layout (vertices=4) out;\n"
681          << "in gl_PerVertex\n"
682          << "{\n"
683          << "  vec4 gl_Position;\n"
684          << "} gl_in[gl_MaxPatchVertices];\n"
685          << "out gl_PerVertex\n"
686          << "{\n"
687          << "  vec4 gl_Position;\n"
688          << "} gl_out[];\n"
689          << "void main() {\n"
690          << "    const float extraLevel = " << extraLevel << ";\n"
691          << "    gl_TessLevelInner[0] = 10.0 + extraLevel;\n"
692          << "    gl_TessLevelInner[1] = 10.0 + extraLevel;\n"
693          << "    gl_TessLevelOuter[0] = 50.0 + extraLevel;\n"
694          << "    gl_TessLevelOuter[1] = 40.0 + extraLevel;\n"
695          << "    gl_TessLevelOuter[2] = 30.0 + extraLevel;\n"
696          << "    gl_TessLevelOuter[3] = 20.0 + extraLevel;\n"
697          << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
698          << "}\n";
699     programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
700 
701     for (uint32_t i = 0u; i < 2u; ++i)
702     {
703         const auto &primType = ((i == 0u) ? m_params.patchTypes.first : m_params.patchTypes.second);
704         const auto &spacing  = ((i == 0u) ? m_params.spacing.first : m_params.spacing.second);
705 
706         std::ostringstream tese;
707         tese << "#version 460\n"
708              << "layout (" << getTessPrimitiveTypeShaderName(primType) << ", " << getSpacingModeShaderName(spacing)
709              << ", ccw) in;\n"
710              << "in gl_PerVertex\n"
711              << "{\n"
712              << "  vec4 gl_Position;\n"
713              << "} gl_in[gl_MaxPatchVertices];\n"
714              << "out gl_PerVertex\n"
715              << "{\n"
716              << "  vec4 gl_Position;\n"
717              << "};\n"
718              << "\n"
719              << "// This assumes 2D, calculates barycentrics for point p inside triangle (a, b, c)\n"
720              << "vec3 calcBaryCoords(vec2 p, vec2 a, vec2 b, vec2 c)\n"
721              << "{\n"
722              << "    const vec2 v0 = b - a;\n"
723              << "    const vec2 v1 = c - a;\n"
724              << "    const vec2 v2 = p - a;\n"
725              << "\n"
726              << "    const float den = v0.x * v1.y - v1.x * v0.y;\n"
727              << "    const float v   = (v2.x * v1.y - v1.x * v2.y) / den;\n"
728              << "    const float w   = (v0.x * v2.y - v2.x * v0.y) / den;\n"
729              << "    const float u   = 1.0 - v - w;\n"
730              << "\n"
731              << "    return vec3(u, v, w);\n"
732              << "}\n"
733              << "\n"
734              << "void main() {\n"
735              << ((primType == TESSPRIMITIVETYPE_QUADS)
736                      // For quads.
737                      ?
738                      "    const float u = gl_TessCoord.x;\n"
739                      "    const float v = gl_TessCoord.y;\n"
740                      "    gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + (1 - u) * v * gl_in[1].gl_Position "
741                      "+ u * (1 - v) * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position;\n"
742                      // For triangles.
743                      :
744                      "    // We have a patch with 4 corners (v0,v1,v2,v3), but triangle-based tessellation.\n"
745                      "    // Lets suppose the triangle covers half the patch (triangle v0,v2,v1).\n"
746                      "    // Expand the triangle by virtually grabbing it from the midpoint between v1 and v2 (which "
747                      "should fall in the middle of the patch) and stretching that point to the fourth corner (v3).\n"
748                      "    const vec4 origpoint = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
749                      "                           (gl_TessCoord.y * gl_in[2].gl_Position) +\n"
750                      "                           (gl_TessCoord.z * gl_in[1].gl_Position);\n"
751                      "    const vec4 midpoint = 0.5 * gl_in[1].gl_Position + 0.5 * gl_in[2].gl_Position;\n"
752                      "\n"
753                      "    // Find out if it falls on left or right side of the triangle.\n"
754                      "    vec4 halfTriangle[3];\n"
755                      "    vec4 stretchedHalf[3];\n"
756                      "\n"
757                      "    if (gl_TessCoord.z >= gl_TessCoord.y)\n"
758                      "    {\n"
759                      "        halfTriangle[0] = gl_in[0].gl_Position;\n"
760                      "        halfTriangle[1] = midpoint;\n"
761                      "        halfTriangle[2] = gl_in[1].gl_Position;\n"
762                      "\n"
763                      "        stretchedHalf[0] = gl_in[0].gl_Position;\n"
764                      "        stretchedHalf[1] = gl_in[3].gl_Position;\n"
765                      "        stretchedHalf[2] = gl_in[1].gl_Position;\n"
766                      "    }\n"
767                      "    else\n"
768                      "    {\n"
769                      "        halfTriangle[0] = gl_in[0].gl_Position;\n"
770                      "        halfTriangle[1] = gl_in[2].gl_Position;\n"
771                      "        halfTriangle[2] = midpoint;\n"
772                      "\n"
773                      "        stretchedHalf[0] = gl_in[0].gl_Position;\n"
774                      "        stretchedHalf[1] = gl_in[2].gl_Position;\n"
775                      "        stretchedHalf[2] = gl_in[3].gl_Position;\n"
776                      "    }\n"
777                      "\n"
778                      "    // Calculate the barycentric coordinates for the left or right sides.\n"
779                      "    vec3 sideBaryCoord = calcBaryCoords(origpoint.xy, halfTriangle[0].xy, halfTriangle[1].xy, "
780                      "halfTriangle[2].xy);\n"
781                      "\n"
782                      "    // Move the point by stretching the half triangle and dragging the midpoint vertex to v3.\n"
783                      "    gl_Position = sideBaryCoord.x * stretchedHalf[0] + sideBaryCoord.y * stretchedHalf[1] + "
784                      "sideBaryCoord.z * stretchedHalf[2];\n")
785              << "}\n";
786         programCollection.glslSources.add("tese" + std::to_string(i)) << glu::TessellationEvaluationSource(tese.str());
787     }
788 
789     std::ostringstream frag;
790     frag << "#version 460\n"
791          << "layout (location=0) out vec4 outColor;\n"
792          << "void main() {\n"
793          << "    outColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
794          << "}\n";
795     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
796 }
797 
iterate(void)798 tcu::TestStatus TessStateSwitchInstance::iterate(void)
799 {
800     const auto &ctx = m_context.getContextCommonData();
801     const tcu::IVec3 fbExtent(128, 128, 1);
802     const auto vkExtent    = makeExtent3D(fbExtent);
803     const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
804     const auto tcuFormat   = mapVkFormat(colorFormat);
805     const auto colorUsage  = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
806     const auto imageType   = VK_IMAGE_TYPE_2D;
807     const auto colorSRR    = makeDefaultImageSubresourceRange();
808     const auto bindPoint   = VK_PIPELINE_BIND_POINT_GRAPHICS;
809 
810     ImageWithBuffer referenceBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType,
811                                     colorSRR);
812     ImageWithBuffer resultBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType,
813                                  colorSRR);
814 
815     // Vertex buffer containing a single full-screen patch.
816     const std::vector<tcu::Vec4> vertices{
817         tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
818         tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
819         tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
820         tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
821     };
822     const auto vertexCount        = de::sizeU32(vertices);
823     const auto patchControlPoints = vertexCount;
824 
825     const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
826     const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
827     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
828     auto &vertexBufferAlloc       = vertexBuffer.getAllocation();
829     void *vertexBufferData        = vertexBufferAlloc.getHostPtr();
830     const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
831 
832     deMemcpy(vertexBufferData, de::dataOrNull(vertices), de::dataSize(vertices));
833     flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
834 
835     const auto pcSize   = static_cast<uint32_t>(sizeof(tcu::Vec2));
836     const auto pcStages = static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_VERTEX_BIT);
837     const auto pcRange  = makePushConstantRange(pcStages, 0u, pcSize);
838 
839     const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
840 
841     const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
842 
843     // Framebuffers.
844     const auto framebuffer0 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, referenceBuffer.getImageView(),
845                                               vkExtent.width, vkExtent.height);
846     const auto framebuffer1 =
847         makeFramebuffer(ctx.vkd, ctx.device, *renderPass, resultBuffer.getImageView(), vkExtent.width, vkExtent.height);
848 
849     // Viewport and scissor.
850     const std::vector<VkViewport> viewports(1u, makeViewport(fbExtent));
851     const std::vector<VkRect2D> scissors(1u, makeRect2D(fbExtent));
852 
853     // Shaders.
854     const auto &binaries   = m_context.getBinaryCollection();
855     const auto vertModule  = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
856     const auto tescModule  = createShaderModule(ctx.vkd, ctx.device, binaries.get("tesc"));
857     const auto teseModule0 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese0"));
858     const auto teseModule1 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese1"));
859     const auto geomModule  = (m_params.geometryShader ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) :
860                                                         Move<VkShaderModule>());
861     const auto fragModule  = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
862 
863     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
864         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
865         nullptr,                                                     // const void* pNext;
866         0u,                                                          // VkPipelineInputAssemblyStateCreateFlags flags;
867         VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,                            // VkPrimitiveTopology topology;
868         VK_FALSE,                                                    // VkBool32 primitiveRestartEnable;
869     };
870 
871     VkPipelineTessellationDomainOriginStateCreateInfo domainOriginStateCreateInfo = {
872         VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // VkStructureType sType;
873         nullptr,                                                                 // const void* pNext;
874         m_params.domainOrigin.first, // VkTessellationDomainOrigin domainOrigin;
875     };
876 
877     const auto tessPNext = (m_params.nonDefaultDomainOrigin() ? &domainOriginStateCreateInfo : nullptr);
878     const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo = {
879         VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
880         tessPNext,                                                 // const void* pNext;
881         0u,                                                        // VkPipelineTessellationStateCreateFlags flags;
882         patchControlPoints,                                        // uint32_t patchControlPoints;
883     };
884 
885     const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
886         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
887         nullptr,                                               // const void* pNext;
888         0u,                                                    // VkPipelineViewportStateCreateFlags flags;
889         de::sizeU32(viewports),                                // uint32_t viewportCount;
890         de::dataOrNull(viewports),                             // const VkViewport* pViewports;
891         de::sizeU32(scissors),                                 // uint32_t scissorCount;
892         de::dataOrNull(scissors),                              // const VkRect2D* pScissors;
893     };
894 
895     // In the rasterization parameters, use wireframe mode to see each triangle if possible.
896     // This makes the test harder to pass by mistake.
897     // We also cull back faces, which will help test domain origin.
898     // The front face changes with the domain origin.
899     const auto frontFace =
900         ((m_params.domainOrigin.second == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT) ?
901              VK_FRONT_FACE_COUNTER_CLOCKWISE // With the default value it's as specified in the shader.
902              :
903              VK_FRONT_FACE_CLOCKWISE); // Otherwise the winding order changes.
904     const auto polygonMode =
905         ((m_context.getDeviceFeatures().fillModeNonSolid) ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL);
906     const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
907         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
908         nullptr,                                                    // const void* pNext;
909         0u,                                                         // VkPipelineRasterizationStateCreateFlags flags;
910         VK_FALSE,                                                   // VkBool32 depthClampEnable;
911         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
912         polygonMode,                                                // VkPolygonMode polygonMode;
913         VK_CULL_MODE_BACK_BIT,                                      // VkCullModeFlags cullMode;
914         frontFace,                                                  // VkFrontFace frontFace;
915         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
916         0.0f,                                                       // float depthBiasConstantFactor;
917         0.0f,                                                       // float depthBiasClamp;
918         0.0f,                                                       // float depthBiasSlopeFactor;
919         1.0f,                                                       // float lineWidth;
920     };
921 
922     // Create two pipelines varying the tessellation evaluation module.
923     const auto pipeline0 =
924         makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, *tescModule, *teseModule0, *geomModule,
925                              *fragModule, *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo,
926                              &tessellationStateCreateInfo, &viewportStateCreateInfo, &rasterizationStateCreateInfo);
927 
928     domainOriginStateCreateInfo.domainOrigin = m_params.domainOrigin.second;
929 
930     const auto pipeline1 =
931         makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, *tescModule, *teseModule1, *geomModule,
932                              *fragModule, *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo,
933                              &tessellationStateCreateInfo, &viewportStateCreateInfo, &rasterizationStateCreateInfo);
934 
935     const auto cmdPool      = makeCommandPool(ctx.vkd, ctx.device, ctx.qfIndex);
936     const auto cmdBufferRef = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
937     const auto cmdBufferRes = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
938 
939     const tcu::Vec2 noOffset(0.0f, 0.0f);
940     const tcu::Vec2 offscreenOffset(50.0f, 50.0f);
941     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
942 
943     // Reference image.
944     beginCommandBuffer(ctx.vkd, *cmdBufferRef);
945     beginRenderPass(ctx.vkd, *cmdBufferRef, *renderPass, *framebuffer0, scissors.at(0u), clearColor);
946     ctx.vkd.cmdBindVertexBuffers(*cmdBufferRef, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
947     ctx.vkd.cmdBindPipeline(*cmdBufferRef, bindPoint, *pipeline1);
948     ctx.vkd.cmdPushConstants(*cmdBufferRef, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
949     ctx.vkd.cmdDraw(*cmdBufferRef, vertexCount, 1u, 0u, 0u);
950     endRenderPass(ctx.vkd, *cmdBufferRef);
951     copyImageToBuffer(ctx.vkd, *cmdBufferRef, referenceBuffer.getImage(), referenceBuffer.getBuffer(),
952                       fbExtent.swizzle(0, 1), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
953                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT,
954                       VK_IMAGE_ASPECT_COLOR_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
955     endCommandBuffer(ctx.vkd, *cmdBufferRef);
956     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRef);
957 
958     // Result image.
959     beginCommandBuffer(ctx.vkd, *cmdBufferRes);
960     beginRenderPass(ctx.vkd, *cmdBufferRes, *renderPass, *framebuffer1, scissors.at(0u), clearColor);
961     ctx.vkd.cmdBindVertexBuffers(*cmdBufferRes, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
962     // Draw offscreen first to force tessellation state emission.
963     ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline0);
964     ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &offscreenOffset);
965     ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
966     // Draw on screen second changing some tessellation state.
967     ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline1);
968     ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
969     ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
970     endRenderPass(ctx.vkd, *cmdBufferRes);
971     copyImageToBuffer(ctx.vkd, *cmdBufferRes, resultBuffer.getImage(), resultBuffer.getBuffer(), fbExtent.swizzle(0, 1),
972                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
973                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
974                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
975     endCommandBuffer(ctx.vkd, *cmdBufferRes);
976     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRes);
977 
978     invalidateAlloc(ctx.vkd, ctx.device, referenceBuffer.getBufferAllocation());
979     invalidateAlloc(ctx.vkd, ctx.device, resultBuffer.getBufferAllocation());
980 
981     tcu::ConstPixelBufferAccess referenceAccess(tcuFormat, fbExtent,
982                                                 referenceBuffer.getBufferAllocation().getHostPtr());
983     tcu::ConstPixelBufferAccess resultAccess(tcuFormat, fbExtent, resultBuffer.getBufferAllocation().getHostPtr());
984 
985     auto &log             = m_context.getTestContext().getLog();
986     const float threshold = 0.005f; // 1/255 < 0.005 < 2/255
987     const tcu::Vec4 thresholdVec(threshold, threshold, threshold, 0.0f);
988 
989     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec,
990                                     tcu::COMPARE_LOG_ON_ERROR))
991         return tcu::TestStatus::fail("Color result does not match reference image -- check log for details");
992 
993     // Render pass and framebuffers.const DeviceCoreFeature requiredDeviceCoreFeature
994     return tcu::TestStatus::pass("Pass");
995 }
996 
getDomainOriginName(VkTessellationDomainOrigin value)997 std::string getDomainOriginName(VkTessellationDomainOrigin value)
998 {
999     static const size_t prefixLen = strlen("VK_TESSELLATION_DOMAIN_ORIGIN_");
1000     std::string nameStr           = getTessellationDomainOriginName(value);
1001 
1002     return de::toLower(nameStr.substr(prefixLen));
1003 }
1004 
1005 } // namespace
1006 
1007 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
createMiscDrawTests(tcu::TestContext & testCtx)1008 tcu::TestCaseGroup *createMiscDrawTests(tcu::TestContext &testCtx)
1009 {
1010     // Miscellaneous draw-result-verifying cases
1011     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc_draw"));
1012 
1013     static const TessPrimitiveType primitivesNoIsolines[] = {
1014         TESSPRIMITIVETYPE_TRIANGLES,
1015         TESSPRIMITIVETYPE_QUADS,
1016     };
1017 
1018     // Triangle fill case
1019     for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1020         for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1021         {
1022             const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1023             const SpacingMode spacingMode         = static_cast<SpacingMode>(spacingModeNdx);
1024             const std::string caseName = std::string() + "fill_cover_" + getTessPrimitiveTypeShaderName(primitiveType) +
1025                                          "_" + getSpacingModeShaderName(spacingMode);
1026 
1027             // Check that there are no obvious gaps in the triangle-filled area of a tessellated shape
1028             addFunctionCaseWithPrograms(
1029                 group.get(), caseName, initProgramsFillCoverCase, runTest,
1030                 makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1031         }
1032 
1033     // Triangle non-overlap case
1034     for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1035         for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1036         {
1037             const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1038             const SpacingMode spacingMode         = static_cast<SpacingMode>(spacingModeNdx);
1039             const std::string caseName            = std::string() + "fill_overlap_" +
1040                                          getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1041                                          getSpacingModeShaderName(spacingMode);
1042 
1043             // Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape
1044             addFunctionCaseWithPrograms(
1045                 group.get(), caseName, initProgramsFillNonOverlapCase, runTest,
1046                 makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1047         }
1048 
1049     // Isolines
1050     for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1051     {
1052         const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1053         const std::string caseName    = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
1054 
1055         // Basic isolines render test
1056         addFunctionCaseWithPrograms(
1057             group.get(), caseName, checkSupportCase, initProgramsIsolinesCase, runTest,
1058             makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, getReferenceImagePathPrefix(caseName)));
1059     }
1060 
1061     // Test switching tessellation parameters on the fly.
1062     for (const auto &geometryShader : {false, true})
1063     {
1064         const auto nameSuffix = (geometryShader ? "_with_geom_shader" : "");
1065 
1066         static const VkTessellationDomainOrigin domainOrigins[] = {
1067             VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
1068             VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
1069         };
1070 
1071         for (const auto &firstPrimitiveType : primitivesNoIsolines)
1072             for (const auto &secondPrimitiveType : primitivesNoIsolines)
1073             {
1074                 if (firstPrimitiveType == secondPrimitiveType)
1075                     continue;
1076 
1077                 const TessStateSwitchParams params{
1078                     std::make_pair(firstPrimitiveType, secondPrimitiveType),
1079                     std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1080                     std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1081                     geometryShader,
1082                 };
1083 
1084                 const auto testName = std::string("switch_primitive_") +
1085                                       getTessPrimitiveTypeShaderName(params.patchTypes.first) + "_to_" +
1086                                       getTessPrimitiveTypeShaderName(params.patchTypes.second) + nameSuffix;
1087                 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1088             }
1089 
1090         for (const auto &firstDomainOrigin : domainOrigins)
1091             for (const auto &secondDomainOrigin : domainOrigins)
1092             {
1093                 if (firstDomainOrigin == secondDomainOrigin)
1094                     continue;
1095 
1096                 const TessStateSwitchParams params{
1097                     std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1098                     std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1099                     std::make_pair(firstDomainOrigin, secondDomainOrigin),
1100                     geometryShader,
1101                 };
1102 
1103                 const auto testName = std::string("switch_domain_origin_") +
1104                                       getDomainOriginName(params.domainOrigin.first) + "_to_" +
1105                                       getDomainOriginName(params.domainOrigin.second) + nameSuffix;
1106                 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1107             }
1108 
1109         for (int firstSpacingModeNdx = 0; firstSpacingModeNdx < SPACINGMODE_LAST; ++firstSpacingModeNdx)
1110             for (int secondSpacingModeNdx = 0; secondSpacingModeNdx < SPACINGMODE_LAST; ++secondSpacingModeNdx)
1111             {
1112                 if (firstSpacingModeNdx == secondSpacingModeNdx)
1113                     continue;
1114 
1115                 const SpacingMode firstSpacingMode  = static_cast<SpacingMode>(firstSpacingModeNdx);
1116                 const SpacingMode secondSpacingMode = static_cast<SpacingMode>(secondSpacingModeNdx);
1117 
1118                 const TessStateSwitchParams params{
1119                     std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1120                     std::make_pair(firstSpacingMode, secondSpacingMode),
1121                     std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1122                     geometryShader,
1123                 };
1124 
1125                 const auto testName = std::string("switch_spacing_mode_") +
1126                                       getSpacingModeShaderName(params.spacing.first) + "_to_" +
1127                                       getSpacingModeShaderName(params.spacing.second) + nameSuffix;
1128                 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1129             }
1130     }
1131 
1132     return group.release();
1133 }
1134 
1135 } // namespace tessellation
1136 } // namespace vkt
1137