555832ce17ed24c41001037785c7f27257257671
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / tessellation / vktTessellationWindingTests.cpp
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 Winding Tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationWindingTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29
30 #include "tcuTestLog.hpp"
31 #include "tcuRGBA.hpp"
32 #include "tcuMaybe.hpp"
33
34 #include "vkDefs.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkStrUtil.hpp"
40
41 #include "deUniquePtr.hpp"
42
43 namespace vkt
44 {
45 namespace tessellation
46 {
47
48 using namespace vk;
49
50 namespace
51 {
52
53 std::string getCaseName (const TessPrimitiveType primitiveType, const Winding winding, bool yFlip)
54 {
55         std::ostringstream str;
56         str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getWindingShaderName(winding);
57         if (yFlip)
58                 str << "_yflip";
59         return str.str();
60 }
61
62 inline VkFrontFace mapFrontFace (const Winding winding)
63 {
64         switch (winding)
65         {
66                 case WINDING_CCW:       return VK_FRONT_FACE_COUNTER_CLOCKWISE;
67                 case WINDING_CW:        return VK_FRONT_FACE_CLOCKWISE;
68                 default:
69                         DE_ASSERT(false);
70                         return VK_FRONT_FACE_LAST;
71         }
72 }
73
74 //! Returns true when the image passes the verification.
75 bool verifyResultImage (tcu::TestLog&                                           log,
76                                                 const tcu::ConstPixelBufferAccess       image,
77                                                 const TessPrimitiveType                         primitiveType,
78                                                 const VkTessellationDomainOriginKHR     domainOrigin,
79                                                 const Winding                                           winding,
80                                                 bool                                                            yFlip,
81                                                 const Winding                                           frontFaceWinding)
82 {
83         const bool                      expectVisiblePrimitive  = ((frontFaceWinding == winding) == (domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR)) != yFlip;
84
85         const int                       totalNumPixels                  = image.getWidth()*image.getHeight();
86
87         const tcu::Vec4         white                                    = tcu::RGBA::white().toVec();
88         const tcu::Vec4         red                                              = tcu::RGBA::red().toVec();
89
90         int                                     numWhitePixels                  = 0;
91         int                                     numRedPixels                    = 0;
92
93         // Count red and white pixels
94         for (int y = 0; y < image.getHeight();  y++)
95         for (int x = 0; x < image.getWidth();   x++)
96         {
97                 numWhitePixels += image.getPixel(x, y) == white ? 1 : 0;
98                 numRedPixels   += image.getPixel(x, y) == red   ? 1 : 0;
99         }
100
101         DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
102
103         log << tcu::TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << tcu::TestLog::EndMessage;
104
105         {
106                 const int otherPixels = totalNumPixels - numWhitePixels - numRedPixels;
107                 if (otherPixels > 0)
108                 {
109                         log << tcu::TestLog::Message
110                                 << "Failure: Got " << otherPixels << " other than white or red pixels"
111                                 << tcu::TestLog::EndMessage;
112                         return false;
113                 }
114         }
115
116         if (expectVisiblePrimitive)
117         {
118                 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
119                 {
120                         const int       badPixelTolerance       = (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(image.getWidth(), image.getHeight()) : 0);
121
122                         if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
123                         {
124                                 log << tcu::TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << tcu::TestLog::EndMessage;
125                                 return false;
126                         }
127
128                         // Check number of filled pixels (from left) in top and bottom rows to
129                         // determine if triangle is in right orientation.
130                         {
131                                 const tcu::IVec2        expectedStart   (0, 1);
132                                 const tcu::IVec2        expectedEnd             (image.getWidth()-1, image.getWidth());
133                                 const tcu::IVec2        expectedTop             = yFlip ? expectedStart : expectedEnd;
134                                 const tcu::IVec2        expectedBottom  = yFlip ? expectedEnd : expectedStart;
135                                 int                                     numTopFilled    = 0;
136                                 int                                     numBottomFilled = 0;
137
138                                 for (int x = 0; x < image.getWidth(); ++x)
139                                 {
140                                         if (image.getPixel(x, 0) == white)
141                                                 numTopFilled += 1;
142                                         else
143                                                 break;
144                                 }
145
146                                 for (int x = 0; x < image.getWidth(); ++x)
147                                 {
148                                         if (image.getPixel(x, image.getHeight()-1) == white)
149                                                 numBottomFilled += 1;
150                                         else
151                                                 break;
152                                 }
153
154                                 if (!de::inBounds(numTopFilled, expectedTop[0], expectedTop[1]) ||
155                                         !de::inBounds(numBottomFilled, expectedBottom[0], expectedBottom[1]))
156                                 {
157                                         log << tcu::TestLog::Message << "Failure: triangle orientation is incorrect" << tcu::TestLog::EndMessage;
158                                         return false;
159                                 }
160                         }
161
162                 }
163                 else if (primitiveType == TESSPRIMITIVETYPE_QUADS)
164                 {
165                         if (numWhitePixels != totalNumPixels)
166                         {
167                                 log << tcu::TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << tcu::TestLog::EndMessage;
168                                 return false;
169                         }
170                 }
171                 else
172                         DE_ASSERT(false);
173         }
174         else
175         {
176                 if (numWhitePixels != 0)
177                 {
178                         log << tcu::TestLog::Message << "Failure: expected only red pixels (everything culled)" << tcu::TestLog::EndMessage;
179                         return false;
180                 }
181         }
182
183         return true;
184 }
185
186 typedef tcu::Maybe<VkTessellationDomainOriginKHR> MaybeDomainOrigin;
187
188 class WindingTest : public TestCase
189 {
190 public:
191                                                                 WindingTest             (tcu::TestContext&                      testCtx,
192                                                                                                  const TessPrimitiveType        primitiveType,
193                                                                                                  const MaybeDomainOrigin&       domainOrigin,
194                                                                                                  const Winding                          winding,
195                                                                                                  bool                                           yFlip);
196
197         void                                            initPrograms    (SourceCollections&                     programCollection) const;
198         TestInstance*                           createInstance  (Context&                                       context) const;
199
200 private:
201         const TessPrimitiveType         m_primitiveType;
202         const MaybeDomainOrigin         m_domainOrigin;
203         const Winding                           m_winding;
204         const bool                                      m_yFlip;
205 };
206
207 WindingTest::WindingTest (tcu::TestContext&                     testCtx,
208                                                   const TessPrimitiveType       primitiveType,
209                                                   const MaybeDomainOrigin&      domainOrigin,
210                                                   const Winding                         winding,
211                                                   bool                                          yFlip)
212         : TestCase                      (testCtx, getCaseName(primitiveType, winding, yFlip), "")
213         , m_primitiveType       (primitiveType)
214         , m_domainOrigin        (domainOrigin)
215         , m_winding                     (winding)
216         , m_yFlip                       (yFlip)
217 {
218 }
219
220 void WindingTest::initPrograms (SourceCollections& programCollection) const
221 {
222         // Vertex shader - no inputs
223         {
224                 std::ostringstream src;
225                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
226                         << "\n"
227                         << "void main (void)\n"
228                         << "{\n"
229                         << "}\n";
230
231                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
232         }
233
234         // Tessellation control shader
235         {
236                 std::ostringstream src;
237                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
238                         << "#extension GL_EXT_tessellation_shader : require\n"
239                         << "\n"
240                         << "layout(vertices = 1) out;\n"
241                         << "\n"
242                         << "void main (void)\n"
243                         << "{\n"
244                         << "    gl_TessLevelInner[0] = 5.0;\n"
245                         << "    gl_TessLevelInner[1] = 5.0;\n"
246                         << "\n"
247                         << "    gl_TessLevelOuter[0] = 5.0;\n"
248                         << "    gl_TessLevelOuter[1] = 5.0;\n"
249                         << "    gl_TessLevelOuter[2] = 5.0;\n"
250                         << "    gl_TessLevelOuter[3] = 5.0;\n"
251                         << "}\n";
252
253                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
254         }
255
256         // Tessellation evaluation shader
257         {
258                 std::ostringstream src;
259                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
260                         << "#extension GL_EXT_tessellation_shader : require\n"
261                         << "\n"
262                         << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ", "
263                                                  << getWindingShaderName(m_winding) << ") in;\n"
264                         << "\n"
265                         << "void main (void)\n"
266                         << "{\n"
267                         << "    gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
268                         << "}\n";
269
270                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
271         }
272
273         // Fragment shader
274         {
275                 std::ostringstream src;
276                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
277                         << "\n"
278                         << "layout(location = 0) out mediump vec4 o_color;\n"
279                         << "\n"
280                         << "void main (void)\n"
281                         << "{\n"
282                         << "    o_color = vec4(1.0);\n"
283                         << "}\n";
284
285                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
286         }
287 }
288
289 class WindingTestInstance : public TestInstance
290 {
291 public:
292                                                                 WindingTestInstance (Context&                                   context,
293                                                                                                          const TessPrimitiveType        primitiveType,
294                                                                                                          const MaybeDomainOrigin&       domainOrigin,
295                                                                                                          const Winding                          winding,
296                                                                                                          bool                                           yFlip);
297
298         tcu::TestStatus                         iterate                         (void);
299
300 private:
301         void                                            requireExtension        (const char* name) const;
302
303         const TessPrimitiveType         m_primitiveType;
304         const MaybeDomainOrigin         m_domainOrigin;
305         const Winding                           m_winding;
306         const bool                                      m_yFlip;
307 };
308
309 WindingTestInstance::WindingTestInstance (Context&                                      context,
310                                                                                   const TessPrimitiveType       primitiveType,
311                                                                                   const MaybeDomainOrigin&      domainOrigin,
312                                                                                   const Winding                         winding,
313                                                                                   bool                                          yFlip)
314         : TestInstance          (context)
315         , m_primitiveType       (primitiveType)
316         , m_domainOrigin        (domainOrigin)
317         , m_winding                     (winding)
318         , m_yFlip                       (yFlip)
319 {
320         if (m_yFlip)
321                 requireExtension("VK_KHR_maintenance1");
322
323         if ((bool)m_domainOrigin)
324                 requireExtension("VK_KHR_maintenance2");
325 }
326
327 void WindingTestInstance::requireExtension (const char* name) const
328 {
329         if (!de::contains(m_context.getDeviceExtensions().begin(), m_context.getDeviceExtensions().end(), name))
330                 TCU_THROW(NotSupportedError, (std::string(name) + " is not supported").c_str());
331 }
332
333 tcu::TestStatus WindingTestInstance::iterate (void)
334 {
335         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
336         const VkDevice                  device                          = m_context.getDevice();
337         const VkQueue                   queue                           = m_context.getUniversalQueue();
338         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
339         Allocator&                              allocator                       = m_context.getDefaultAllocator();
340
341         // Color attachment
342
343         const tcu::IVec2                          renderSize                             = tcu::IVec2(64, 64);
344         const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
345         const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
346         const Image                                       colorAttachmentImage           (vk, device, allocator,
347                                                                                                                          makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
348                                                                                                                          MemoryRequirement::Any);
349
350         // Color output buffer: image will be copied here for verification
351
352         const VkDeviceSize      colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
353         const Buffer            colorBuffer                      (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
354
355         // Pipeline
356
357         const Unique<VkImageView>               colorAttachmentView(makeImageView                       (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
358         const Unique<VkRenderPass>              renderPass         (makeRenderPass                      (vk, device, colorFormat));
359         const Unique<VkFramebuffer>             framebuffer        (makeFramebuffer                     (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
360         const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayoutWithoutDescriptors(vk, device));
361
362         const VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
363
364         // Front face is static state, so we have to create two pipelines.
365
366         const Unique<VkPipeline> pipelineCounterClockwise(GraphicsPipelineBuilder()
367                 .setCullModeFlags                               (cullMode)
368                 .setFrontFace                                   (VK_FRONT_FACE_COUNTER_CLOCKWISE)
369                 .setShader                                              (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                   m_context.getBinaryCollection().get("vert"), DE_NULL)
370                 .setShader                                              (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), DE_NULL)
371                 .setShader                                              (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
372                 .setShader                                              (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                 m_context.getBinaryCollection().get("frag"), DE_NULL)
373                 .setTessellationDomainOrigin    (m_domainOrigin)
374                 .build                                                  (vk, device, *pipelineLayout, *renderPass));
375
376         const Unique<VkPipeline> pipelineClockwise(GraphicsPipelineBuilder()
377                 .setCullModeFlags                               (cullMode)
378                 .setFrontFace                                   (VK_FRONT_FACE_CLOCKWISE)
379                 .setShader                                              (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                   m_context.getBinaryCollection().get("vert"), DE_NULL)
380                 .setShader                                              (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,     m_context.getBinaryCollection().get("tesc"), DE_NULL)
381                 .setShader                                              (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
382                 .setShader                                              (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                 m_context.getBinaryCollection().get("frag"), DE_NULL)
383                 .setTessellationDomainOrigin    (m_domainOrigin)
384                 .build                                                  (vk, device, *pipelineLayout, *renderPass));
385
386         const struct // not static
387         {
388                 Winding         frontFaceWinding;
389                 VkPipeline      pipeline;
390         } testCases[] =
391         {
392                 { WINDING_CCW,  *pipelineCounterClockwise },
393                 { WINDING_CW,   *pipelineClockwise                },
394         };
395
396         tcu::TestLog& log = m_context.getTestContext().getLog();
397         log << tcu::TestLog::Message << "Pipeline uses " << getCullModeFlagsStr(cullMode) << tcu::TestLog::EndMessage;
398
399         bool success = true;
400
401         // Draw commands
402
403         const Unique<VkCommandPool>   cmdPool  (makeCommandPool  (vk, device, queueFamilyIndex));
404         const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
405
406         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCases); ++caseNdx)
407         {
408                 const Winding frontFaceWinding = testCases[caseNdx].frontFaceWinding;
409
410                 log << tcu::TestLog::Message << "Setting " << getFrontFaceName(mapFrontFace(frontFaceWinding)) << tcu::TestLog::EndMessage;
411
412                 // Reset the command buffer and begin.
413                 beginCommandBuffer(vk, *cmdBuffer);
414
415                 // Change color attachment image layout
416                 {
417                         // State is slightly different on the first iteration.
418                         const VkImageLayout currentLayout = (caseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
419                         const VkAccessFlags srcFlags      = (caseNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
420
421                         const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
422                                 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
423                                 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
424                                 *colorAttachmentImage, colorImageSubresourceRange);
425
426                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
427                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
428                 }
429
430                 // Begin render pass
431                 {
432                         const VkRect2D renderArea = {
433                                 makeOffset2D(0, 0),
434                                 makeExtent2D(renderSize.x(), renderSize.y()),
435                         };
436                         const tcu::Vec4 clearColor = tcu::RGBA::red().toVec();
437
438                         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
439                 }
440
441                 const VkViewport viewport =
442                 {
443                         0.0f,                                                                                                                   // float        x;
444                         m_yFlip ? static_cast<float>(renderSize.y()) : 0.0f,                    // float        y;
445                         static_cast<float>(renderSize.x()),                                                             // float        width;
446                         static_cast<float>(m_yFlip ? -renderSize.y() : renderSize.y()), // float        height;
447                         0.0f,                                                                                                                   // float        minDepth;
448                         1.0f,                                                                                                                   // float        maxDepth;
449                 };
450                 vk.cmdSetViewport(*cmdBuffer, 0, 1, &viewport);
451
452                 const VkRect2D scissor =
453                 {
454                         makeOffset2D(0, 0),
455                         makeExtent2D(renderSize.x(), renderSize.y()),
456                 };
457                 vk.cmdSetScissor(*cmdBuffer, 0, 1, &scissor);
458
459                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, testCases[caseNdx].pipeline);
460
461                 // Process a single abstract vertex.
462                 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
463                 endRenderPass(vk, *cmdBuffer);
464
465                 // Copy render result to a host-visible buffer
466                 {
467                         const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
468                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
469                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
470                                 *colorAttachmentImage, colorImageSubresourceRange);
471
472                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
473                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
474                 }
475                 {
476                         const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
477                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
478                 }
479                 {
480                         const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
481                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
482
483                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
484                                 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
485                 }
486
487                 endCommandBuffer(vk, *cmdBuffer);
488                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
489
490                 {
491                         // Log rendered image
492                         const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
493                         invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes);
494
495                         const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
496                         log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
497
498                         // Verify case result
499                         success = verifyResultImage(log,
500                                                                                 imagePixelAccess,
501                                                                                 m_primitiveType,
502                                                                                 !m_domainOrigin ? VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR : *m_domainOrigin,
503                                                                                 m_winding,
504                                                                                 m_yFlip,
505                                                                                 frontFaceWinding) && success;
506                 }
507         }  // for windingNdx
508
509         return (success ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
510 }
511
512 TestInstance* WindingTest::createInstance (Context& context) const
513 {
514         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
515
516         return new WindingTestInstance(context, m_primitiveType, m_domainOrigin, m_winding, m_yFlip);
517 }
518
519 void populateWindingGroup (tcu::TestCaseGroup* group, tcu::Maybe<VkTessellationDomainOriginKHR> domainOrigin)
520 {
521         static const TessPrimitiveType primitivesNoIsolines[] =
522         {
523                 TESSPRIMITIVETYPE_TRIANGLES,
524                 TESSPRIMITIVETYPE_QUADS,
525         };
526
527         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
528         for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
529         {
530                 group->addChild(new WindingTest(group->getTestContext(), primitivesNoIsolines[primitiveTypeNdx], domainOrigin, (Winding)windingNdx, false));
531                 group->addChild(new WindingTest(group->getTestContext(), primitivesNoIsolines[primitiveTypeNdx], domainOrigin, (Winding)windingNdx, true));
532         }
533 }
534
535 } // anonymous
536
537 //! These tests correspond to dEQP-GLES31.functional.tessellation.winding.*
538 tcu::TestCaseGroup* createWindingTests (tcu::TestContext& testCtx)
539 {
540         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "winding", "Test the cw and ccw input layout qualifiers"));
541
542         addTestGroup(group.get(), "default_domain",             "No tessellation domain specified",     populateWindingGroup,   tcu::nothing<VkTessellationDomainOriginKHR>());
543         addTestGroup(group.get(), "lower_left_domain",  "Lower left tessellation domain",       populateWindingGroup,   tcu::just(VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR));
544         addTestGroup(group.get(), "upper_left_domain",  "Upper left tessellation domain",       populateWindingGroup,   tcu::just(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR));
545
546         return group.release();
547 }
548
549 } // tessellation
550 } // vkt