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 Common Edge Tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationCommonEdgeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28
29 #include "tcuTestLog.hpp"
30 #include "tcuTexture.hpp"
31
32 #include "vkDefs.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkStrUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkBufferWithMemory.hpp"
42 #include "vkImageWithMemory.hpp"
43
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46
47 #include <string>
48 #include <vector>
49
50 namespace vkt
51 {
52 namespace tessellation
53 {
54
55 using namespace vk;
56
57 namespace
58 {
59
60 enum CaseType
61 {
62 CASETYPE_BASIC =
63 0, //!< Order patch vertices such that when two patches share a vertex, it's at the same index for both.
64 CASETYPE_PRECISE, //!< Vertex indices don't match like for CASETYPE_BASIC, but other measures are taken, using the 'precise' qualifier.
65
66 CASETYPE_LAST
67 };
68
69 struct CaseDefinition
70 {
71 TessPrimitiveType primitiveType;
72 SpacingMode spacingMode;
73 CaseType caseType;
74 };
75
76 //! Check that a certain rectangle in the image contains no black pixels.
77 //! Returns true if an image successfully passess the verification.
verifyResult(tcu::TestLog & log,const tcu::ConstPixelBufferAccess image)78 bool verifyResult(tcu::TestLog &log, const tcu::ConstPixelBufferAccess image)
79 {
80 const int startX = static_cast<int>(0.15f * (float)image.getWidth());
81 const int endX = static_cast<int>(0.85f * (float)image.getWidth());
82 const int startY = static_cast<int>(0.15f * (float)image.getHeight());
83 const int endY = static_cast<int>(0.85f * (float)image.getHeight());
84
85 for (int y = startY; y < endY; ++y)
86 for (int x = startX; x < endX; ++x)
87 {
88 const tcu::Vec4 pixel = image.getPixel(x, y);
89
90 if (pixel.x() == 0 && pixel.y() == 0 && pixel.z() == 0)
91 {
92 log << tcu::TestLog::Message << "Failure: there seem to be cracks in the rendered result"
93 << tcu::TestLog::EndMessage << tcu::TestLog::Message
94 << "Note: pixel with zero r, g and b channels found at " << tcu::IVec2(x, y)
95 << tcu::TestLog::EndMessage;
96
97 return false;
98 }
99 }
100
101 log << tcu::TestLog::Message << "Success: there seem to be no cracks in the rendered result"
102 << tcu::TestLog::EndMessage;
103
104 return true;
105 }
106
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)107 void initPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
108 {
109 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
110
111 // Vertex shader
112 {
113 std::ostringstream src;
114 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
115 << "\n"
116 << "layout(location = 0) in highp vec2 in_v_position;\n"
117 << "layout(location = 1) in highp float in_v_tessParam;\n"
118 << "\n"
119 << "layout(location = 0) out highp vec2 in_tc_position;\n"
120 << "layout(location = 1) out highp float in_tc_tessParam;\n"
121 << "\n"
122 << "void main (void)\n"
123 << "{\n"
124 << " in_tc_position = in_v_position;\n"
125 << " in_tc_tessParam = in_v_tessParam;\n"
126 << "}\n";
127
128 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
129 }
130
131 // Tessellation control shader
132 {
133 const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
134
135 std::ostringstream src;
136 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
137 << "#extension GL_EXT_tessellation_shader : require\n"
138 << (caseDef.caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "") << "\n"
139 << "layout(vertices = " << numVertices << ") out;\n"
140 << "\n"
141 << "layout(location = 0) in highp vec2 in_tc_position[];\n"
142 << "layout(location = 1) in highp float in_tc_tessParam[];\n"
143 << "\n"
144 << "layout(location = 0) out highp vec2 in_te_position[];\n"
145 << "\n"
146 << (caseDef.caseType == CASETYPE_PRECISE ? "precise gl_TessLevelOuter;\n\n" : "") << "void main (void)\n"
147 << "{\n"
148 << " in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
149 << "\n"
150 << " gl_TessLevelInner[0] = 5.0;\n"
151 << " gl_TessLevelInner[1] = 5.0;\n"
152 << "\n"
153 << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
154 " gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);\n"
155 " gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);\n"
156 " gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);\n" :
157 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
158 " gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[2]);\n"
159 " gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[0]);\n"
160 " gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[3] + in_tc_tessParam[1]);\n"
161 " gl_TessLevelOuter[3] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[3]);\n" :
162 "")
163 << "}\n";
164
165 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
166 }
167
168 // Tessellation evaluation shader
169 {
170 std::ostringstream primitiveSpecificCode;
171 if (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
172 primitiveSpecificCode << " highp vec2 pos = gl_TessCoord.x*in_te_position[0] + "
173 "gl_TessCoord.y*in_te_position[1] + gl_TessCoord.z*in_te_position[2];\n"
174 << "\n"
175 << " highp float f = sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, "
176 "gl_TessCoord.z))) * 0.5 + 0.5;\n"
177 << " in_f_color = vec4(gl_TessCoord*f, 1.0);\n";
178 else if (caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
179 primitiveSpecificCode
180 << (caseDef.caseType == CASETYPE_BASIC ?
181 " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0]\n"
182 " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1]\n"
183 " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*in_te_position[2]\n"
184 " + ( gl_TessCoord.x)*( gl_TessCoord.y)*in_te_position[3];\n" :
185 caseDef.caseType == CASETYPE_PRECISE ?
186 " highp vec2 a = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0];\n"
187 " highp vec2 b = ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1];\n"
188 " highp vec2 c = (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*in_te_position[2];\n"
189 " highp vec2 d = ( gl_TessCoord.x)*( gl_TessCoord.y)*in_te_position[3];\n"
190 " highp vec2 pos = a+b+c+d;\n" :
191 "")
192 << "\n"
193 << " highp float f = sqrt(1.0 - 2.0 * max(abs(gl_TessCoord.x - 0.5), abs(gl_TessCoord.y - "
194 "0.5)))*0.5 + 0.5;\n"
195 << " in_f_color = vec4(0.1, gl_TessCoord.xy*f, 1.0);\n";
196
197 std::ostringstream src;
198 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
199 << "#extension GL_EXT_tessellation_shader : require\n"
200 << (caseDef.caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "") << "\n"
201 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
202 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
203 << "\n"
204 << "layout(location = 0) in highp vec2 in_te_position[];\n"
205 << "\n"
206 << "layout(location = 0) out mediump vec4 in_f_color;\n"
207 << "\n"
208 << (caseDef.caseType == CASETYPE_PRECISE ? "precise gl_Position;\n\n" : "") << "void main (void)\n"
209 << "{\n"
210 << primitiveSpecificCode.str() << "\n"
211 << " // Offset the position slightly, based on the parity of the bits in the float representation.\n"
212 << " // This is done to detect possible small differences in edge vertex positions between patches.\n"
213 << " uvec2 bits = floatBitsToUint(pos);\n"
214 << " uint numBits = 0u;\n"
215 << " for (uint i = 0u; i < 32u; i++)\n"
216 << " numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
217 << " pos += float(numBits&1u)*0.04;\n"
218 << "\n"
219 << " gl_Position = vec4(pos, 0.0, 1.0);\n"
220 << "}\n";
221
222 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
223 }
224
225 // Fragment shader
226 {
227 std::ostringstream src;
228 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
229 << "\n"
230 << "layout(location = 0) in mediump vec4 in_f_color;\n"
231 << "\n"
232 << "layout(location = 0) out mediump vec4 o_color;\n"
233 << "\n"
234 << "void main (void)\n"
235 << "{\n"
236 << " o_color = in_f_color;\n"
237 << "}\n";
238
239 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
240 }
241 }
242
243 //! Generic test code used by all test cases.
test(Context & context,const CaseDefinition caseDef)244 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
245 {
246 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
247 DE_ASSERT(caseDef.caseType == CASETYPE_BASIC || caseDef.caseType == CASETYPE_PRECISE);
248
249 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
250
251 const DeviceInterface &vk = context.getDeviceInterface();
252 const VkDevice device = context.getDevice();
253 const VkQueue queue = context.getUniversalQueue();
254 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
255 Allocator &allocator = context.getDefaultAllocator();
256
257 // Prepare test data
258
259 std::vector<float> gridPosComps;
260 std::vector<float> gridTessParams;
261 std::vector<uint16_t> gridIndices;
262
263 {
264 const int gridWidth = 4;
265 const int gridHeight = 4;
266 const int numVertices = (gridWidth + 1) * (gridHeight + 1);
267 const int numIndices =
268 gridWidth * gridHeight * (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 * 2 : 4);
269 const int numPosCompsPerVertex = 2;
270 const int totalNumPosComps = numPosCompsPerVertex * numVertices;
271
272 gridPosComps.reserve(totalNumPosComps);
273 gridTessParams.reserve(numVertices);
274 gridIndices.reserve(numIndices);
275
276 {
277 for (int i = 0; i < gridHeight + 1; ++i)
278 for (int j = 0; j < gridWidth + 1; ++j)
279 {
280 gridPosComps.push_back(-1.0f + 2.0f * ((float)j + 0.5f) / (float)(gridWidth + 1));
281 gridPosComps.push_back(-1.0f + 2.0f * ((float)i + 0.5f) / (float)(gridHeight + 1));
282 gridTessParams.push_back((float)(i * (gridWidth + 1) + j) / (float)(numVertices - 1));
283 }
284 }
285
286 // Generate patch vertex indices.
287 // \note If CASETYPE_BASIC, the vertices are ordered such that when multiple
288 // triangles/quads share a vertex, it's at the same index for everyone.
289
290 if (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
291 {
292 for (int i = 0; i < gridHeight; i++)
293 for (int j = 0; j < gridWidth; j++)
294 {
295 const uint16_t corners[4] = {
296 (uint16_t)((i + 0) * (gridWidth + 1) + j + 0), (uint16_t)((i + 0) * (gridWidth + 1) + j + 1),
297 (uint16_t)((i + 1) * (gridWidth + 1) + j + 0), (uint16_t)((i + 1) * (gridWidth + 1) + j + 1)};
298
299 const int secondTriangleVertexIndexOffset = caseDef.caseType == CASETYPE_BASIC ? 0 : 1;
300
301 for (int k = 0; k < 3; k++)
302 gridIndices.push_back(corners[(k + 0 + i + (2 - j % 3)) % 3]);
303 for (int k = 0; k < 3; k++)
304 gridIndices.push_back(
305 corners[(k + 2 + i + (2 - j % 3) + secondTriangleVertexIndexOffset) % 3 + 1]);
306 }
307 }
308 else if (caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
309 {
310 for (int i = 0; i < gridHeight; ++i)
311 for (int j = 0; j < gridWidth; ++j)
312 {
313 for (int m = 0; m < 2; m++)
314 for (int n = 0; n < 2; n++)
315 gridIndices.push_back((uint16_t)((i + (i + m) % 2) * (gridWidth + 1) + j + (j + n) % 2));
316
317 if (caseDef.caseType == CASETYPE_PRECISE && (i + j) % 2 == 0)
318 std::reverse(gridIndices.begin() + (gridIndices.size() - 4),
319 gridIndices.begin() + gridIndices.size());
320 }
321 }
322 else
323 DE_ASSERT(false);
324
325 DE_ASSERT(static_cast<int>(gridPosComps.size()) == totalNumPosComps);
326 DE_ASSERT(static_cast<int>(gridTessParams.size()) == numVertices);
327 DE_ASSERT(static_cast<int>(gridIndices.size()) == numIndices);
328 }
329
330 // Vertex input buffer: we put both attributes and indices in here.
331
332 const VkDeviceSize vertexDataSizeBytes =
333 sizeInBytes(gridPosComps) + sizeInBytes(gridTessParams) + sizeInBytes(gridIndices);
334 const std::size_t vertexPositionsOffset = 0;
335 const std::size_t vertexTessParamsOffset = sizeInBytes(gridPosComps);
336 const std::size_t vertexIndicesOffset = vertexTessParamsOffset + sizeInBytes(gridTessParams);
337
338 const BufferWithMemory vertexBuffer(
339 vk, device, allocator,
340 makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
341 MemoryRequirement::HostVisible);
342
343 {
344 const Allocation &alloc = vertexBuffer.getAllocation();
345 uint8_t *const pData = static_cast<uint8_t *>(alloc.getHostPtr());
346
347 deMemcpy(pData + vertexPositionsOffset, &gridPosComps[0], static_cast<std::size_t>(sizeInBytes(gridPosComps)));
348 deMemcpy(pData + vertexTessParamsOffset, &gridTessParams[0],
349 static_cast<std::size_t>(sizeInBytes(gridTessParams)));
350 deMemcpy(pData + vertexIndicesOffset, &gridIndices[0], static_cast<std::size_t>(sizeInBytes(gridIndices)));
351
352 flushAlloc(vk, device, alloc);
353 // No barrier needed, flushed memory is automatically visible
354 }
355
356 // Color attachment
357
358 const tcu::IVec2 renderSize = tcu::IVec2(256, 256);
359 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
360 const VkImageSubresourceRange colorImageSubresourceRange =
361 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
362 const ImageWithMemory colorAttachmentImage(
363 vk, device, allocator,
364 makeImageCreateInfo(renderSize, colorFormat,
365 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
366 MemoryRequirement::Any);
367
368 // Color output buffer: image will be copied here for verification
369
370 const VkDeviceSize colorBufferSizeBytes =
371 renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
372 const BufferWithMemory colorBuffer(vk, device, allocator,
373 makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
374 MemoryRequirement::HostVisible);
375
376 // Pipeline
377
378 const Unique<VkImageView> colorAttachmentView(makeImageView(
379 vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
380 const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, colorFormat));
381 const Unique<VkFramebuffer> framebuffer(
382 makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
383 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
384 const Unique<VkCommandBuffer> cmdBuffer(
385 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
386 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device));
387
388 const int inPatchSize = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
389 const Unique<VkPipeline> pipeline(
390 GraphicsPipelineBuilder()
391 .setRenderSize(renderSize)
392 .setPatchControlPoints(inPatchSize)
393 .addVertexBinding(makeVertexInputBindingDescription(0u, sizeof(tcu::Vec2), VK_VERTEX_INPUT_RATE_VERTEX))
394 .addVertexBinding(makeVertexInputBindingDescription(1u, sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX))
395 .addVertexAttribute(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u))
396 .addVertexAttribute(makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32_SFLOAT, 0u))
397 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL)
398 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"),
399 DE_NULL)
400 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
401 context.getBinaryCollection().get("tese"), DE_NULL)
402 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL)
403 .build(vk, device, *pipelineLayout, *renderPass));
404
405 // Draw commands
406
407 beginCommandBuffer(vk, *cmdBuffer);
408
409 // Change color attachment image layout
410 {
411 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
412 (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
413 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorAttachmentImage, colorImageSubresourceRange);
414
415 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
416 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u,
417 &colorAttachmentLayoutBarrier);
418 }
419
420 // Begin render pass
421 {
422 const VkRect2D renderArea = makeRect2D(renderSize);
423 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
424
425 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
426 }
427
428 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
429 {
430 const VkBuffer buffers[] = {*vertexBuffer, *vertexBuffer};
431 const VkDeviceSize offsets[] = {
432 vertexPositionsOffset,
433 vertexTessParamsOffset,
434 };
435 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, DE_LENGTH_OF_ARRAY(buffers), buffers, offsets);
436
437 vk.cmdBindIndexBuffer(*cmdBuffer, *vertexBuffer, vertexIndicesOffset, VK_INDEX_TYPE_UINT16);
438 }
439
440 vk.cmdDrawIndexed(*cmdBuffer, static_cast<uint32_t>(gridIndices.size()), 1u, 0u, 0, 0u);
441 endRenderPass(vk, *cmdBuffer);
442
443 // Copy render result to a host-visible buffer
444 copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
445
446 endCommandBuffer(vk, *cmdBuffer);
447 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
448
449 {
450 // Log the result image.
451
452 const Allocation &colorBufferAlloc = colorBuffer.getAllocation();
453
454 invalidateAlloc(vk, device, colorBufferAlloc);
455
456 const tcu::ConstPixelBufferAccess imagePixelAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1,
457 colorBufferAlloc.getHostPtr());
458 tcu::TestLog &log = context.getTestContext().getLog();
459
460 log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess) << tcu::TestLog::Message
461 << "Note: coloring is done to clarify the positioning and orientation of the "
462 << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "triangles" :
463 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ? "quads" :
464 "")
465 << "; the color of a vertex corresponds to the index of that vertex in the patch"
466 << tcu::TestLog::EndMessage;
467
468 if (caseDef.caseType == CASETYPE_BASIC)
469 log << tcu::TestLog::Message
470 << "Note: each shared vertex has the same index among the primitives it belongs to"
471 << tcu::TestLog::EndMessage;
472 else if (caseDef.caseType == CASETYPE_PRECISE)
473 log << tcu::TestLog::Message << "Note: the 'precise' qualifier is used to avoid cracks between primitives"
474 << tcu::TestLog::EndMessage;
475 else
476 DE_ASSERT(false);
477
478 // Verify the result.
479 const bool ok = verifyResult(log, imagePixelAccess);
480 return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
481 }
482 }
483
getCaseName(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const CaseType caseType)484 std::string getCaseName(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const CaseType caseType)
485 {
486 std::ostringstream str;
487 str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getSpacingModeShaderName(spacingMode)
488 << (caseType == CASETYPE_PRECISE ? "_precise" : "");
489 return str.str();
490 }
491
492 } // namespace
493
494 //! These tests correspond to dEQP-GLES31.functional.tessellation.common_edge.*
createCommonEdgeTests(tcu::TestContext & testCtx)495 tcu::TestCaseGroup *createCommonEdgeTests(tcu::TestContext &testCtx)
496 {
497 // Draw multiple adjacent shapes and check that no cracks appear between them
498 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "common_edge"));
499
500 static const TessPrimitiveType primitiveTypes[] = {
501 TESSPRIMITIVETYPE_TRIANGLES,
502 TESSPRIMITIVETYPE_QUADS,
503 };
504
505 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
506 for (int caseTypeNdx = 0; caseTypeNdx < CASETYPE_LAST; ++caseTypeNdx)
507 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
508 {
509 const TessPrimitiveType primitiveType = primitiveTypes[primitiveTypeNdx];
510 const CaseType caseType = static_cast<CaseType>(caseTypeNdx);
511 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
512 const CaseDefinition caseDef = {primitiveType, spacingMode, caseType};
513
514 addFunctionCaseWithPrograms(group.get(), getCaseName(primitiveType, spacingMode, caseType),
515 initPrograms, test, caseDef);
516 }
517
518 return group.release();
519 }
520
521 } // namespace tessellation
522 } // namespace vkt
523