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