41891aff09d8c0b378960930219b54571c3e76f7
[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
29 #include "tcuTestLog.hpp"
30 #include "tcuRGBA.hpp"
31
32 #include "vkDefs.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkStrUtil.hpp"
38
39 #include "deUniquePtr.hpp"
40
41 namespace vkt
42 {
43 namespace tessellation
44 {
45
46 using namespace vk;
47
48 namespace
49 {
50
51 std::string getCaseName (const TessPrimitiveType primitiveType, const Winding winding)
52 {
53         std::ostringstream str;
54         str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getWindingShaderName(winding);
55         return str.str();
56 }
57
58 inline VkFrontFace mapFrontFace (const Winding winding)
59 {
60         switch (winding)
61         {
62                 case WINDING_CCW:       return VK_FRONT_FACE_COUNTER_CLOCKWISE;
63                 case WINDING_CW:        return VK_FRONT_FACE_CLOCKWISE;
64                 default:
65                         DE_ASSERT(false);
66                         return VK_FRONT_FACE_LAST;
67         }
68 }
69
70 //! Returns true when the image passes the verification.
71 bool verifyResultImage (tcu::TestLog&                                           log,
72                                                 const tcu::ConstPixelBufferAccess       image,
73                                                 const TessPrimitiveType                         primitiveType,
74                                                 const Winding                                           winding,
75                                                 const Winding                                           frontFaceWinding)
76 {
77         const int totalNumPixels        = image.getWidth()*image.getHeight();
78         const int badPixelTolerance = (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(image.getWidth(), image.getHeight()) : 0);
79
80         const tcu::Vec4 white = tcu::RGBA::white().toVec();
81         const tcu::Vec4 red   = tcu::RGBA::red().toVec();
82
83         int numWhitePixels = 0;
84         int numRedPixels   = 0;
85         for (int y = 0; y < image.getHeight();  y++)
86         for (int x = 0; x < image.getWidth();   x++)
87         {
88                 numWhitePixels += image.getPixel(x, y) == white ? 1 : 0;
89                 numRedPixels   += image.getPixel(x, y) == red   ? 1 : 0;
90         }
91
92         DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
93
94         log << tcu::TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << tcu::TestLog::EndMessage;
95
96         const int otherPixels = totalNumPixels - numWhitePixels - numRedPixels;
97         if (otherPixels > badPixelTolerance)
98         {
99                 log << tcu::TestLog::Message
100                         << "Failure: Got " << otherPixels << " other than white or red pixels (maximum tolerance " << badPixelTolerance << ")"
101                         << tcu::TestLog::EndMessage;
102                 return false;
103         }
104
105         if (frontFaceWinding == winding)
106         {
107                 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
108                 {
109                         if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
110                         {
111                                 log << tcu::TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << tcu::TestLog::EndMessage;
112                                 return false;
113                         }
114                 }
115                 else if (primitiveType == TESSPRIMITIVETYPE_QUADS)
116                 {
117                         if (numWhitePixels != totalNumPixels)
118                         {
119                                 log << tcu::TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << tcu::TestLog::EndMessage;
120                                 return false;
121                         }
122                 }
123                 else
124                         DE_ASSERT(false);
125         }
126         else
127         {
128                 if (numWhitePixels != 0)
129                 {
130                         log << tcu::TestLog::Message << "Failure: expected only red pixels (everything culled)" << tcu::TestLog::EndMessage;
131                         return false;
132                 }
133         }
134
135         return true;
136 }
137
138 class WindingTest : public TestCase
139 {
140 public:
141                                                                 WindingTest             (tcu::TestContext&                      testCtx,
142                                                                                                  const TessPrimitiveType        primitiveType,
143                                                                                                  const Winding                          winding);
144
145         void                                            initPrograms    (SourceCollections&                     programCollection) const;
146         TestInstance*                           createInstance  (Context&                                       context) const;
147
148 private:
149         const TessPrimitiveType         m_primitiveType;
150         const Winding                           m_winding;
151 };
152
153 WindingTest::WindingTest (tcu::TestContext&                     testCtx,
154                                                   const TessPrimitiveType       primitiveType,
155                                                   const Winding                         winding)
156         : TestCase                      (testCtx, getCaseName(primitiveType, winding), "")
157         , m_primitiveType       (primitiveType)
158         , m_winding                     (winding)
159 {
160 }
161
162 void WindingTest::initPrograms (SourceCollections& programCollection) const
163 {
164         // Vertex shader - no inputs
165         {
166                 std::ostringstream src;
167                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
168                         << "\n"
169                         << "void main (void)\n"
170                         << "{\n"
171                         << "}\n";
172
173                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
174         }
175
176         // Tessellation control shader
177         {
178                 std::ostringstream src;
179                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
180                         << "#extension GL_EXT_tessellation_shader : require\n"
181                         << "\n"
182                         << "layout(vertices = 1) out;\n"
183                         << "\n"
184                         << "void main (void)\n"
185                         << "{\n"
186                         << "    gl_TessLevelInner[0] = 5.0;\n"
187                         << "    gl_TessLevelInner[1] = 5.0;\n"
188                         << "\n"
189                         << "    gl_TessLevelOuter[0] = 5.0;\n"
190                         << "    gl_TessLevelOuter[1] = 5.0;\n"
191                         << "    gl_TessLevelOuter[2] = 5.0;\n"
192                         << "    gl_TessLevelOuter[3] = 5.0;\n"
193                         << "}\n";
194
195                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
196         }
197
198         // Tessellation evaluation shader
199         {
200                 std::ostringstream src;
201                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
202                         << "#extension GL_EXT_tessellation_shader : require\n"
203                         << "\n"
204                         << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ", "
205                                                  << getWindingShaderName(m_winding) << ") in;\n"
206                         << "\n"
207                         << "void main (void)\n"
208                         << "{\n"
209                         << "    gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
210                         << "}\n";
211
212                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
213         }
214
215         // Fragment shader
216         {
217                 std::ostringstream src;
218                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
219                         << "\n"
220                         << "layout(location = 0) out mediump vec4 o_color;\n"
221                         << "\n"
222                         << "void main (void)\n"
223                         << "{\n"
224                         << "    o_color = vec4(1.0);\n"
225                         << "}\n";
226
227                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
228         }
229 }
230
231 class WindingTestInstance : public TestInstance
232 {
233 public:
234                                                                 WindingTestInstance (Context&                                   context,
235                                                                                                          const TessPrimitiveType        primitiveType,
236                                                                                                          const Winding                          winding);
237
238         tcu::TestStatus                         iterate                         (void);
239
240 private:
241         const TessPrimitiveType         m_primitiveType;
242         const Winding                           m_winding;
243 };
244
245 WindingTestInstance::WindingTestInstance (Context&                                      context,
246                                                                                   const TessPrimitiveType       primitiveType,
247                                                                                   const Winding                         winding)
248         : TestInstance          (context)
249         , m_primitiveType       (primitiveType)
250         , m_winding                     (winding)
251 {
252 }
253
254 tcu::TestStatus WindingTestInstance::iterate (void)
255 {
256         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
257         const VkDevice                  device                          = m_context.getDevice();
258         const VkQueue                   queue                           = m_context.getUniversalQueue();
259         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
260         Allocator&                              allocator                       = m_context.getDefaultAllocator();
261
262         // Color attachment
263
264         const tcu::IVec2                          renderSize                             = tcu::IVec2(64, 64);
265         const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
266         const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
267         const Image                                       colorAttachmentImage           (vk, device, allocator,
268                                                                                                                          makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
269                                                                                                                          MemoryRequirement::Any);
270
271         // Color output buffer: image will be copied here for verification
272
273         const VkDeviceSize      colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
274         const Buffer            colorBuffer                      (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
275
276         // Pipeline
277
278         const Unique<VkImageView>               colorAttachmentView(makeImageView                       (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
279         const Unique<VkRenderPass>              renderPass         (makeRenderPass                      (vk, device, colorFormat));
280         const Unique<VkFramebuffer>             framebuffer        (makeFramebuffer                     (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
281         const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayoutWithoutDescriptors(vk, device));
282
283         const VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
284
285         // Front face is static state, so we have to create two pipelines.
286
287         const Unique<VkPipeline> pipelineCounterClockwise(GraphicsPipelineBuilder()
288                 .setRenderSize   (renderSize)
289                 .setCullModeFlags(cullMode)
290                 .setFrontFace    (VK_FRONT_FACE_COUNTER_CLOCKWISE)
291                 .setShader               (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                  m_context.getBinaryCollection().get("vert"), DE_NULL)
292                 .setShader               (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), DE_NULL)
293                 .setShader               (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
294                 .setShader               (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                m_context.getBinaryCollection().get("frag"), DE_NULL)
295                 .build                   (vk, device, *pipelineLayout, *renderPass));
296
297         const Unique<VkPipeline> pipelineClockwise(GraphicsPipelineBuilder()
298                 .setRenderSize   (renderSize)
299                 .setCullModeFlags(cullMode)
300                 .setFrontFace    (VK_FRONT_FACE_CLOCKWISE)
301                 .setShader               (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                  m_context.getBinaryCollection().get("vert"), DE_NULL)
302                 .setShader               (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), DE_NULL)
303                 .setShader               (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
304                 .setShader               (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                                m_context.getBinaryCollection().get("frag"), DE_NULL)
305                 .build                   (vk, device, *pipelineLayout, *renderPass));
306
307         const struct // not static
308         {
309                 Winding         frontFaceWinding;
310                 VkPipeline      pipeline;
311         } testCases[] =
312         {
313                 { WINDING_CCW,  *pipelineCounterClockwise },
314                 { WINDING_CW,   *pipelineClockwise                },
315         };
316
317         tcu::TestLog& log = m_context.getTestContext().getLog();
318         log << tcu::TestLog::Message << "Pipeline uses " << getCullModeFlagsStr(cullMode) << tcu::TestLog::EndMessage;
319
320         bool success = true;
321
322         // Draw commands
323
324         const Unique<VkCommandPool>   cmdPool  (makeCommandPool  (vk, device, queueFamilyIndex));
325         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
326
327         for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCases); ++caseNdx)
328         {
329                 const Winding frontFaceWinding = testCases[caseNdx].frontFaceWinding;
330
331                 log << tcu::TestLog::Message << "Setting " << getFrontFaceName(mapFrontFace(frontFaceWinding)) << tcu::TestLog::EndMessage;
332
333                 // Reset the command buffer and begin.
334                 beginCommandBuffer(vk, *cmdBuffer);
335
336                 // Change color attachment image layout
337                 {
338                         // State is slightly different on the first iteration.
339                         const VkImageLayout currentLayout = (caseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
340                         const VkAccessFlags srcFlags      = (caseNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
341
342                         const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
343                                 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
344                                 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
345                                 *colorAttachmentImage, colorImageSubresourceRange);
346
347                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
348                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
349                 }
350
351                 // Begin render pass
352                 {
353                         const VkRect2D renderArea = {
354                                 makeOffset2D(0, 0),
355                                 makeExtent2D(renderSize.x(), renderSize.y()),
356                         };
357                         const tcu::Vec4 clearColor = tcu::RGBA::red().toVec();
358
359                         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
360                 }
361
362                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, testCases[caseNdx].pipeline);
363
364                 // Process a single abstract vertex.
365                 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
366                 endRenderPass(vk, *cmdBuffer);
367
368                 // Copy render result to a host-visible buffer
369                 {
370                         const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
371                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
372                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
373                                 *colorAttachmentImage, colorImageSubresourceRange);
374
375                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
376                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
377                 }
378                 {
379                         const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
380                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
381                 }
382                 {
383                         const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
384                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
385
386                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
387                                 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
388                 }
389
390                 endCommandBuffer(vk, *cmdBuffer);
391                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
392
393                 {
394                         // Log rendered image
395                         const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
396                         invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes);
397
398                         const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
399                         log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
400
401                         // Verify case result
402                         success = success && verifyResultImage(log, imagePixelAccess, m_primitiveType, m_winding, frontFaceWinding);
403                 }
404         }  // for windingNdx
405
406         return (success ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
407 }
408
409 TestInstance* WindingTest::createInstance (Context& context) const
410 {
411         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
412
413         return new WindingTestInstance(context, m_primitiveType, m_winding);
414 }
415
416 } // anonymous
417
418 //! These tests correspond to dEQP-GLES31.functional.tessellation.winding.*
419 tcu::TestCaseGroup* createWindingTests (tcu::TestContext& testCtx)
420 {
421         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "winding", "Test the cw and ccw input layout qualifiers"));
422
423         static const TessPrimitiveType primitivesNoIsolines[] =
424         {
425                 TESSPRIMITIVETYPE_TRIANGLES,
426                 TESSPRIMITIVETYPE_QUADS,
427         };
428
429         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
430         for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
431                 group->addChild(new WindingTest(testCtx, primitivesNoIsolines[primitiveTypeNdx], (Winding)windingNdx));
432
433         return group.release();
434 }
435
436 } // tessellation
437 } // vkt