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