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 (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 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(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)); 435 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ©Region); 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 516