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