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