1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2014 The Android Open Source Project
6 * Copyright (c) 2016 The Khronos Group Inc.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Tessellation Coordinates Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktTessellationCoordinatesTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuRGBA.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "tcuVectorUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkTypeUtil.hpp"
40 #include "deUniquePtr.hpp"
47 namespace tessellation
59 bool operator() (const T& a, const T& b) const { return a.size() < b.size(); }
62 std::string getCaseName (const TessPrimitiveType primitiveType, const SpacingMode spacingMode)
64 std::ostringstream str;
65 str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getSpacingModeShaderName(spacingMode);
69 std::vector<TessLevels> genTessLevelCases (const TessPrimitiveType primitiveType,
70 const SpacingMode spacingMode)
72 static const TessLevels rawTessLevelCases[] =
74 { { 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
75 { { 63.0f, 24.0f }, { 15.0f, 42.0f, 10.0f, 12.0f } },
76 { { 3.0f, 2.0f }, { 6.0f, 8.0f, 7.0f, 9.0f } },
77 { { 4.0f, 6.0f }, { 2.0f, 3.0f, 1.0f, 4.0f } },
78 { { 2.0f, 2.0f }, { 6.0f, 8.0f, 7.0f, 9.0f } },
79 { { 5.0f, 6.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
80 { { 1.0f, 6.0f }, { 2.0f, 3.0f, 1.0f, 4.0f } },
81 { { 5.0f, 1.0f }, { 2.0f, 3.0f, 1.0f, 4.0f } },
82 { { 5.2f, 1.6f }, { 2.9f, 3.4f, 1.5f, 4.1f } }
85 if (spacingMode == SPACINGMODE_EQUAL)
86 return std::vector<TessLevels>(DE_ARRAY_BEGIN(rawTessLevelCases), DE_ARRAY_END(rawTessLevelCases));
89 std::vector<TessLevels> result;
90 result.reserve(DE_LENGTH_OF_ARRAY(rawTessLevelCases));
92 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(rawTessLevelCases); ++tessLevelCaseNdx)
94 TessLevels curTessLevelCase = rawTessLevelCases[tessLevelCaseNdx];
96 float* const inner = &curTessLevelCase.inner[0];
97 float* const outer = &curTessLevelCase.outer[0];
99 for (int j = 0; j < 2; ++j) inner[j] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[j]));
100 for (int j = 0; j < 4; ++j) outer[j] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, outer[j]));
102 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
104 if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f)
106 if (inner[0] == 1.0f)
107 inner[0] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[0] + 0.1f));
110 else if (primitiveType == TESSPRIMITIVETYPE_QUADS)
112 if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f || outer[3] > 1.0f)
114 if (inner[0] == 1.0f) inner[0] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[0] + 0.1f));
115 if (inner[1] == 1.0f) inner[1] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[1] + 0.1f));
119 result.push_back(curTessLevelCase);
122 DE_ASSERT(static_cast<int>(result.size()) == DE_LENGTH_OF_ARRAY(rawTessLevelCases));
127 std::vector<tcu::Vec3> generateReferenceTessCoords (const TessPrimitiveType primitiveType,
128 const SpacingMode spacingMode,
129 const float* innerLevels,
130 const float* outerLevels)
132 if (isPatchDiscarded(primitiveType, outerLevels))
133 return std::vector<tcu::Vec3>();
135 switch (primitiveType)
137 case TESSPRIMITIVETYPE_TRIANGLES:
141 getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
143 if (spacingMode != SPACINGMODE_EQUAL)
145 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
146 DE_ASSERT(de::abs(innerLevels[0] - static_cast<float>(inner)) < 0.001f);
147 for (int i = 0; i < 3; ++i)
148 DE_ASSERT(de::abs(outerLevels[i] - static_cast<float>(outer[i])) < 0.001f);
149 DE_ASSERT(inner > 1 || (outer[0] == 1 && outer[1] == 1 && outer[2] == 1));
152 return generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]);
155 case TESSPRIMITIVETYPE_QUADS:
159 getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
161 if (spacingMode != SPACINGMODE_EQUAL)
163 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
164 for (int i = 0; i < 2; ++i)
165 DE_ASSERT(de::abs(innerLevels[i] - static_cast<float>(inner[i])) < 0.001f);
166 for (int i = 0; i < 4; ++i)
167 DE_ASSERT(de::abs(outerLevels[i] - static_cast<float>(outer[i])) < 0.001f);
169 DE_ASSERT((inner[0] > 1 && inner[1] > 1) || (inner[0] == 1 && inner[1] == 1 && outer[0] == 1 && outer[1] == 1 && outer[2] == 1 && outer[3] == 1));
172 return generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
175 case TESSPRIMITIVETYPE_ISOLINES:
178 getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
180 if (spacingMode != SPACINGMODE_EQUAL)
182 // \note For fractional spacing modes, exact results are implementation-defined except in special cases.
183 DE_ASSERT(de::abs(outerLevels[1] - static_cast<float>(outer[1])) < 0.001f);
186 return generateReferenceIsolineTessCoords(outer[0], outer[1]);
191 return std::vector<tcu::Vec3>();
195 void drawPoint (tcu::Surface& dst, const int centerX, const int centerY, const tcu::RGBA& color, const int size)
197 const int width = dst.getWidth();
198 const int height = dst.getHeight();
199 DE_ASSERT(de::inBounds(centerX, 0, width) && de::inBounds(centerY, 0, height));
202 for (int yOff = -((size-1)/2); yOff <= size/2; ++yOff)
203 for (int xOff = -((size-1)/2); xOff <= size/2; ++xOff)
205 const int pixX = centerX + xOff;
206 const int pixY = centerY + yOff;
207 if (de::inBounds(pixX, 0, width) && de::inBounds(pixY, 0, height))
208 dst.setPixel(pixX, pixY, color);
212 void drawTessCoordPoint (tcu::Surface& dst, const TessPrimitiveType primitiveType, const tcu::Vec3& pt, const tcu::RGBA& color, const int size)
214 // \note These coordinates should match the description in the log message in TessCoordTestInstance::iterate.
216 static const tcu::Vec2 triangleCorners[3] =
218 tcu::Vec2(0.95f, 0.95f),
219 tcu::Vec2(0.5f, 0.95f - 0.9f*deFloatSqrt(3.0f/4.0f)),
220 tcu::Vec2(0.05f, 0.95f)
223 static const float quadIsolineLDRU[4] =
225 0.1f, 0.9f, 0.9f, 0.1f
228 const tcu::Vec2 dstPos = primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? pt.x()*triangleCorners[0]
229 + pt.y()*triangleCorners[1]
230 + pt.z()*triangleCorners[2]
232 : primitiveType == TESSPRIMITIVETYPE_QUADS ||
233 primitiveType == TESSPRIMITIVETYPE_ISOLINES ? tcu::Vec2((1.0f - pt.x())*quadIsolineLDRU[0] + pt.x()*quadIsolineLDRU[2],
234 (1.0f - pt.y())*quadIsolineLDRU[1] + pt.y()*quadIsolineLDRU[3])
239 static_cast<int>(dstPos.x() * (float)dst.getWidth()),
240 static_cast<int>(dstPos.y() * (float)dst.getHeight()),
245 void drawTessCoordVisualization (tcu::Surface& dst, const TessPrimitiveType primitiveType, const std::vector<tcu::Vec3>& coords)
247 const int imageWidth = 256;
248 const int imageHeight = 256;
249 dst.setSize(imageWidth, imageHeight);
251 tcu::clear(dst.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
253 for (int i = 0; i < static_cast<int>(coords.size()); ++i)
254 drawTessCoordPoint(dst, primitiveType, coords[i], tcu::RGBA::white(), 2);
257 inline bool vec3XLessThan (const tcu::Vec3& a, const tcu::Vec3& b)
259 return a.x() < b.x();
262 int binarySearchFirstVec3WithXAtLeast (const std::vector<tcu::Vec3>& sorted, float x)
264 const tcu::Vec3 ref(x, 0.0f, 0.0f);
265 const std::vector<tcu::Vec3>::const_iterator first = std::lower_bound(sorted.begin(), sorted.end(), ref, vec3XLessThan);
266 if (first == sorted.end())
268 return static_cast<int>(std::distance(sorted.begin(), first));
271 // Check that all points in subset are (approximately) present also in superset.
272 bool oneWayComparePointSets (tcu::TestLog& log,
273 tcu::Surface& errorDst,
274 const TessPrimitiveType primitiveType,
275 const std::vector<tcu::Vec3>& subset,
276 const std::vector<tcu::Vec3>& superset,
277 const char* subsetName,
278 const char* supersetName,
279 const tcu::RGBA& errorColor)
281 const std::vector<tcu::Vec3> supersetSorted = sorted(superset, vec3XLessThan);
282 const float epsilon = 0.01f;
283 const int maxNumFailurePrints = 5;
284 int numFailuresDetected = 0;
286 for (int subNdx = 0; subNdx < static_cast<int>(subset.size()); ++subNdx)
288 const tcu::Vec3& subPt = subset[subNdx];
290 bool matchFound = false;
293 // Binary search the index of the first point in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
294 const tcu::Vec3 matchMin = subPt - epsilon;
295 const tcu::Vec3 matchMax = subPt + epsilon;
296 const int firstCandidateNdx = binarySearchFirstVec3WithXAtLeast(supersetSorted, matchMin.x());
298 if (firstCandidateNdx >= 0)
300 // Compare subPt to all points in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
301 for (int superNdx = firstCandidateNdx; superNdx < static_cast<int>(supersetSorted.size()) && supersetSorted[superNdx].x() <= matchMax.x(); ++superNdx)
303 const tcu::Vec3& superPt = supersetSorted[superNdx];
305 if (tcu::boolAll(tcu::greaterThanEqual (superPt, matchMin)) &&
306 tcu::boolAll(tcu::lessThanEqual (superPt, matchMax)))
317 ++numFailuresDetected;
318 if (numFailuresDetected < maxNumFailurePrints)
319 log << tcu::TestLog::Message << "Failure: no matching " << supersetName << " point found for " << subsetName << " point " << subPt << tcu::TestLog::EndMessage;
320 else if (numFailuresDetected == maxNumFailurePrints)
321 log << tcu::TestLog::Message << "Note: More errors follow" << tcu::TestLog::EndMessage;
323 drawTessCoordPoint(errorDst, primitiveType, subPt, errorColor, 4);
327 return numFailuresDetected == 0;
330 //! Returns true on matching coordinate sets.
331 bool compareTessCoords (tcu::TestLog& log,
332 TessPrimitiveType primitiveType,
333 const std::vector<tcu::Vec3>& refCoords,
334 const std::vector<tcu::Vec3>& resCoords)
336 tcu::Surface refVisual;
337 tcu::Surface resVisual;
340 drawTessCoordVisualization(refVisual, primitiveType, refCoords);
341 drawTessCoordVisualization(resVisual, primitiveType, resCoords);
343 // Check that all points in reference also exist in result.
344 success = oneWayComparePointSets(log, refVisual, primitiveType, refCoords, resCoords, "reference", "result", tcu::RGBA::blue()) && success;
345 // Check that all points in result also exist in reference.
346 success = oneWayComparePointSets(log, resVisual, primitiveType, resCoords, refCoords, "result", "reference", tcu::RGBA::red()) && success;
350 log << tcu::TestLog::Message << "Note: in the following reference visualization, points that are missing in result point set are blue (if any)" << tcu::TestLog::EndMessage
351 << tcu::TestLog::Image("RefTessCoordVisualization", "Reference tessCoord visualization", refVisual)
352 << tcu::TestLog::Message << "Note: in the following result visualization, points that are missing in reference point set are red (if any)" << tcu::TestLog::EndMessage;
355 log << tcu::TestLog::Image("ResTessCoordVisualization", "Result tessCoord visualization", resVisual);
360 class TessCoordTest : public TestCase
363 TessCoordTest (tcu::TestContext& testCtx,
364 const TessPrimitiveType primitiveType,
365 const SpacingMode spacingMode);
367 void initPrograms (SourceCollections& programCollection) const;
368 TestInstance* createInstance (Context& context) const;
371 const TessPrimitiveType m_primitiveType;
372 const SpacingMode m_spacingMode;
375 TessCoordTest::TessCoordTest (tcu::TestContext& testCtx,
376 const TessPrimitiveType primitiveType,
377 const SpacingMode spacingMode)
378 : TestCase (testCtx, getCaseName(primitiveType, spacingMode), "")
379 , m_primitiveType (primitiveType)
380 , m_spacingMode (spacingMode)
384 void TessCoordTest::initPrograms (SourceCollections& programCollection) const
386 // Vertex shader - no inputs
388 std::ostringstream src;
389 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
391 << "void main (void)\n"
395 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
398 // Tessellation control shader
400 std::ostringstream src;
401 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
402 << "#extension GL_EXT_tessellation_shader : require\n"
404 << "layout(vertices = 1) out;\n"
406 << "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
407 << " float inner0;\n"
408 << " float inner1;\n"
409 << " float outer0;\n"
410 << " float outer1;\n"
411 << " float outer2;\n"
412 << " float outer3;\n"
415 << "void main (void)\n"
417 << " gl_TessLevelInner[0] = sb_levels.inner0;\n"
418 << " gl_TessLevelInner[1] = sb_levels.inner1;\n"
420 << " gl_TessLevelOuter[0] = sb_levels.outer0;\n"
421 << " gl_TessLevelOuter[1] = sb_levels.outer1;\n"
422 << " gl_TessLevelOuter[2] = sb_levels.outer2;\n"
423 << " gl_TessLevelOuter[3] = sb_levels.outer3;\n"
426 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
429 // Tessellation evaluation shader
431 std::ostringstream src;
432 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
433 << "#extension GL_EXT_tessellation_shader : require\n"
435 << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ", "
436 << getSpacingModeShaderName(m_spacingMode) << ", point_mode) in;\n"
438 << "layout(set = 0, binding = 1, std430) coherent restrict buffer Output {\n"
439 << " int numInvocations;\n"
440 << " vec3 tessCoord[];\n" // alignment is 16 bytes, same as vec4
443 << "void main (void)\n"
445 << " int index = atomicAdd(sb_out.numInvocations, 1);\n"
446 << " sb_out.tessCoord[index] = gl_TessCoord;\n"
449 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
453 class TessCoordTestInstance : public TestInstance
456 TessCoordTestInstance (Context& context,
457 const TessPrimitiveType primitiveType,
458 const SpacingMode spacingMode);
460 tcu::TestStatus iterate (void);
463 const TessPrimitiveType m_primitiveType;
464 const SpacingMode m_spacingMode;
467 TessCoordTestInstance::TessCoordTestInstance (Context& context,
468 const TessPrimitiveType primitiveType,
469 const SpacingMode spacingMode)
470 : TestInstance (context)
471 , m_primitiveType (primitiveType)
472 , m_spacingMode (spacingMode)
476 tcu::TestStatus TessCoordTestInstance::iterate (void)
478 const DeviceInterface& vk = m_context.getDeviceInterface();
479 const VkDevice device = m_context.getDevice();
480 const VkQueue queue = m_context.getUniversalQueue();
481 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
482 Allocator& allocator = m_context.getDefaultAllocator();
486 const std::vector<TessLevels> tessLevelCases = genTessLevelCases(m_primitiveType, m_spacingMode);
487 std::vector<std::vector<tcu::Vec3> > allReferenceTessCoords (tessLevelCases.size());
489 for (deUint32 i = 0; i < tessLevelCases.size(); ++i)
490 allReferenceTessCoords[i] = generateReferenceTessCoords(m_primitiveType, m_spacingMode, &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]);
492 const size_t maxNumVertices = static_cast<int>(std::max_element(allReferenceTessCoords.begin(), allReferenceTessCoords.end(), SizeLessThan<std::vector<tcu::Vec3> >())->size());
494 // Input buffer: tessellation levels. Data is filled in later.
496 const Buffer tessLevelsBuffer(vk, device, allocator,
497 makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
499 // Output buffer: number of invocations + padding + tessellation coordinates. Initialized later.
501 const int resultBufferTessCoordsOffset = 4 * (int)sizeof(deInt32);
502 const int extraneousVertices = 16; // allow some room for extraneous vertices from duplicate shader invocations (number is arbitrary)
503 const VkDeviceSize resultBufferSizeBytes = resultBufferTessCoordsOffset + (maxNumVertices + extraneousVertices)*sizeof(tcu::Vec4);
504 const Buffer resultBuffer (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
508 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
509 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
510 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
513 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
514 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
515 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
516 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
518 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
520 const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
521 const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
523 DescriptorSetUpdateBuilder()
524 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
525 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
528 // Pipeline: set up vertex processing without rasterization
530 const Unique<VkRenderPass> renderPass (makeRenderPassWithoutAttachments (vk, device));
531 const Unique<VkFramebuffer> framebuffer (makeFramebufferWithoutAttachments(vk, device, *renderPass));
532 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
533 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
534 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
536 const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
537 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), DE_NULL)
538 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), DE_NULL)
539 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
540 .build (vk, device, *pipelineLayout, *renderPass));
542 deUint32 numPassedCases = 0;
544 // Repeat the test for all tessellation coords cases
545 for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
547 m_context.getTestContext().getLog()
548 << tcu::TestLog::Message
549 << "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], m_primitiveType)
550 << tcu::TestLog::EndMessage;
552 // Upload tessellation levels data to the input buffer
554 const Allocation& alloc = tessLevelsBuffer.getAllocation();
555 TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
556 *bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
557 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
560 // Clear the results buffer
562 const Allocation& alloc = resultBuffer.getAllocation();
563 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes));
564 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), resultBufferSizeBytes);
567 // Reset the command buffer and begin recording.
568 beginCommandBuffer(vk, *cmdBuffer);
569 beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
571 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
572 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
574 // Process a single abstract vertex.
575 vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
576 endRenderPass(vk, *cmdBuffer);
579 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
580 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
582 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
583 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
586 endCommandBuffer(vk, *cmdBuffer);
587 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
591 const Allocation& resultAlloc = resultBuffer.getAllocation();
592 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), resultBufferSizeBytes);
594 const deInt32 numResults = *static_cast<deInt32*>(resultAlloc.getHostPtr());
595 const std::vector<tcu::Vec3> resultTessCoords = readInterleavedData<tcu::Vec3>(numResults, resultAlloc.getHostPtr(), resultBufferTessCoordsOffset, sizeof(tcu::Vec4));
596 const std::vector<tcu::Vec3>& referenceTessCoords = allReferenceTessCoords[tessLevelCaseNdx];
597 const int numExpectedResults = static_cast<int>(referenceTessCoords.size());
598 tcu::TestLog& log = m_context.getTestContext().getLog();
600 if (numResults < numExpectedResults)
602 log << tcu::TestLog::Message
603 << "Failure: generated " << numResults << " coordinates, but the expected reference value is " << numExpectedResults
604 << tcu::TestLog::EndMessage;
606 else if (numResults == numExpectedResults)
607 log << tcu::TestLog::Message << "Note: generated " << numResults << " tessellation coordinates" << tcu::TestLog::EndMessage;
610 log << tcu::TestLog::Message
611 << "Note: generated " << numResults << " coordinates (out of which " << numExpectedResults << " must be unique)"
612 << tcu::TestLog::EndMessage;
615 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
616 log << tcu::TestLog::Message << "Note: in the following visualization(s), the u=1, v=1, w=1 corners are at the right, top, and left corners, respectively" << tcu::TestLog::EndMessage;
617 else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
618 log << tcu::TestLog::Message << "Note: in the following visualization(s), u and v coordinate go left-to-right and bottom-to-top, respectively" << tcu::TestLog::EndMessage;
622 if (compareTessCoords(log, m_primitiveType, referenceTessCoords, resultTessCoords) && (numResults >= numExpectedResults))
625 } // for tessLevelCaseNdx
627 return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Some cases have failed"));
630 TestInstance* TessCoordTest::createInstance (Context& context) const
632 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
634 return new TessCoordTestInstance(context, m_primitiveType, m_spacingMode);
639 //! Based on dEQP-GLES31.functional.tessellation.tesscoord.*
640 //! \note Transform feedback is replaced with SSBO. Because of that, this version allows duplicate coordinates from shader invocations.
641 //! The test still fails if not enough coordinates are generated, or if coordinates don't match the reference data.
642 tcu::TestCaseGroup* createCoordinatesTests (tcu::TestContext& testCtx)
644 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "tesscoord", "Tessellation coordinates tests"));
646 for (int primitiveTypeNdx = 0; primitiveTypeNdx < TESSPRIMITIVETYPE_LAST; ++primitiveTypeNdx)
647 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
648 group->addChild(new TessCoordTest(testCtx, (TessPrimitiveType)primitiveTypeNdx, (SpacingMode)spacingModeNdx));
650 return group.release();