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 Shader Input/Output Tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktTessellationShaderInputOutputTests.hpp" 26 #include "vktTestCaseUtil.hpp" 27 #include "vktTessellationUtil.hpp" 28 29 #include "tcuTestLog.hpp" 30 #include "tcuImageIO.hpp" 31 #include "tcuTexture.hpp" 32 #include "tcuImageCompare.hpp" 33 34 #include "vkDefs.hpp" 35 #include "vkQueryUtil.hpp" 36 #include "vkBuilderUtil.hpp" 37 #include "vkImageUtil.hpp" 38 #include "vkTypeUtil.hpp" 39 #include "vkStrUtil.hpp" 40 41 #include "deUniquePtr.hpp" 42 #include "deStringUtil.hpp" 43 44 #include <string> 45 #include <vector> 46 47 namespace vkt 48 { 49 namespace tessellation 50 { 51 52 using namespace vk; 53 54 namespace 55 { 56 57 enum Constants 58 { 59 RENDER_SIZE = 256, 60 }; 61 62 //! Generic test code used by all test cases. 63 tcu::TestStatus runTest (Context& context, 64 const int numPrimitives, 65 const int inPatchSize, 66 const int outPatchSize, 67 const VkFormat vertexFormat, 68 const void* vertexData, 69 const VkDeviceSize vertexDataSizeBytes, 70 const tcu::ConstPixelBufferAccess& referenceImageAccess) 71 { 72 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER); 73 74 const DeviceInterface& vk = context.getDeviceInterface(); 75 const VkDevice device = context.getDevice(); 76 const VkQueue queue = context.getUniversalQueue(); 77 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 78 Allocator& allocator = context.getDefaultAllocator(); 79 80 // Vertex input: may be just some abstract numbers 81 82 const Buffer vertexBuffer(vk, device, allocator, 83 makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible); 84 85 { 86 const Allocation& alloc = vertexBuffer.getAllocation(); 87 deMemcpy(alloc.getHostPtr(), vertexData, static_cast<std::size_t>(vertexDataSizeBytes)); 88 89 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes); 90 // No barrier needed, flushed memory is automatically visible 91 } 92 93 // Color attachment 94 95 const tcu::IVec2 renderSize = tcu::IVec2(RENDER_SIZE, RENDER_SIZE); 96 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 97 const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 98 const Image colorAttachmentImage (vk, device, allocator, 99 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u), 100 MemoryRequirement::Any); 101 102 // Color output buffer: image will be copied here for verification 103 104 const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)); 105 const Buffer colorBuffer (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible); 106 107 // Pipeline 108 109 const Unique<VkImageView> colorAttachmentView(makeImageView (vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange)); 110 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, colorFormat)); 111 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u)); 112 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayoutWithoutDescriptors(vk, device)); 113 const Unique<VkCommandPool> cmdPool (makeCommandPool (vk, device, queueFamilyIndex)); 114 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 115 116 const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder() 117 .setRenderSize (renderSize) 118 .setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat))) 119 .setPatchControlPoints (inPatchSize) 120 .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL) 121 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"), DE_NULL) 122 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL) 123 .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL) 124 .build (vk, device, *pipelineLayout, *renderPass)); 125 126 { 127 tcu::TestLog& log = context.getTestContext().getLog(); 128 log << tcu::TestLog::Message 129 << "Note: input patch size is " << inPatchSize << ", output patch size is " << outPatchSize 130 << tcu::TestLog::EndMessage; 131 } 132 133 // Draw commands 134 135 beginCommandBuffer(vk, *cmdBuffer); 136 137 // Change color attachment image layout 138 { 139 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier( 140 (VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 141 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 142 *colorAttachmentImage, colorImageSubresourceRange); 143 144 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 145 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier); 146 } 147 148 // Begin render pass 149 { 150 const VkRect2D renderArea = { 151 makeOffset2D(0, 0), 152 makeExtent2D(renderSize.x(), renderSize.y()), 153 }; 154 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f); 155 156 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); 157 } 158 159 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 160 { 161 const VkDeviceSize vertexBufferOffset = 0ull; 162 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); 163 } 164 165 // Process enough vertices to make a patch. 166 vk.cmdDraw(*cmdBuffer, numPrimitives * inPatchSize, 1u, 0u, 0u); 167 endRenderPass(vk, *cmdBuffer); 168 169 // Copy render result to a host-visible buffer 170 { 171 const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier( 172 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 173 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 174 *colorAttachmentImage, colorImageSubresourceRange); 175 176 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 177 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier); 178 } 179 { 180 const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u)); 181 vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ©Region); 182 } 183 { 184 const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier( 185 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes); 186 187 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 188 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL); 189 } 190 191 endCommandBuffer(vk, *cmdBuffer); 192 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 193 194 { 195 const Allocation& colorBufferAlloc = colorBuffer.getAllocation(); 196 invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes); 197 198 // Verify case result 199 const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr()); 200 tcu::TestLog& log = context.getTestContext().getLog(); 201 const bool ok = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", referenceImageAccess, resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT); 202 203 return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure")); 204 } 205 } 206 207 namespace PatchVertexCount 208 { 209 210 struct CaseDefinition 211 { 212 int inPatchSize; 213 int outPatchSize; 214 std::string referenceImagePath; 215 }; 216 217 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef) 218 { 219 // Vertex shader 220 { 221 std::ostringstream src; 222 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 223 << "\n" 224 << "layout(location = 0) in highp float in_v_attr;\n" 225 << "layout(location = 0) out highp float in_tc_attr;\n" 226 << "\n" 227 << "void main (void)\n" 228 << "{\n" 229 << " in_tc_attr = in_v_attr;\n" 230 << "}\n"; 231 232 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 233 } 234 235 // Tessellation control shader 236 { 237 std::ostringstream src; 238 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 239 << "#extension GL_EXT_tessellation_shader : require\n" 240 << "\n" 241 << "layout(vertices = " << caseDef.outPatchSize << ") out;\n" 242 << "\n" 243 << "layout(location = 0) in highp float in_tc_attr[];\n" 244 << "layout(location = 0) out highp float in_te_attr[];\n" 245 << "\n" 246 << "void main (void)\n" 247 << "{\n" 248 << " in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" << caseDef.inPatchSize << "/" << caseDef.outPatchSize << "];\n" 249 << "\n" 250 << " gl_TessLevelInner[0] = 5.0;\n" 251 << " gl_TessLevelInner[1] = 5.0;\n" 252 << "\n" 253 << " gl_TessLevelOuter[0] = 5.0;\n" 254 << " gl_TessLevelOuter[1] = 5.0;\n" 255 << " gl_TessLevelOuter[2] = 5.0;\n" 256 << " gl_TessLevelOuter[3] = 5.0;\n" 257 << "}\n"; 258 259 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 260 } 261 262 // Tessellation evaluation shader 263 { 264 std::ostringstream src; 265 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 266 << "#extension GL_EXT_tessellation_shader : require\n" 267 << "\n" 268 << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n" 269 << "\n" 270 << "layout(location = 0) in highp float in_te_attr[];\n" 271 << "layout(location = 0) out mediump vec4 in_f_color;\n" 272 << "\n" 273 << "void main (void)\n" 274 << "{\n" 275 << " highp float x = gl_TessCoord.x*2.0 - 1.0;\n" 276 << " highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << caseDef.outPatchSize << "-1)))];\n" 277 << " gl_Position = vec4(x, y, 0.0, 1.0);\n" 278 << " in_f_color = vec4(1.0);\n" 279 << "}\n"; 280 281 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 282 } 283 284 // Fragment shader 285 { 286 std::ostringstream src; 287 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 288 << "\n" 289 << "layout(location = 0) in mediump vec4 in_f_color;\n" 290 << "layout(location = 0) out mediump vec4 o_color;\n" 291 << "\n" 292 << "void main (void)\n" 293 << "{\n" 294 << " o_color = in_f_color;\n" 295 << "}\n"; 296 297 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 298 } 299 } 300 301 tcu::TestStatus test (Context& context, const CaseDefinition caseDef) 302 { 303 // Input vertex attribute data 304 std::vector<float> vertexData; 305 vertexData.reserve(caseDef.inPatchSize); 306 for (int i = 0; i < caseDef.inPatchSize; ++i) 307 { 308 const float f = static_cast<float>(i) / static_cast<float>(caseDef.inPatchSize - 1); 309 vertexData.push_back(f*f); 310 } 311 const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size(); 312 313 // Load reference image 314 tcu::TextureLevel referenceImage; 315 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str()); 316 317 const int numPrimitives = 1; 318 319 return runTest(context, numPrimitives, caseDef.inPatchSize, caseDef.outPatchSize, 320 VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess()); 321 } 322 323 } // PatchVertexCountTest ns 324 325 namespace PerPatchData 326 { 327 328 enum CaseType 329 { 330 CASETYPE_PRIMITIVE_ID_TCS, 331 CASETYPE_PRIMITIVE_ID_TES, 332 CASETYPE_PATCH_VERTICES_IN_TCS, 333 CASETYPE_PATCH_VERTICES_IN_TES, 334 CASETYPE_TESS_LEVEL_INNER0_TES, 335 CASETYPE_TESS_LEVEL_INNER1_TES, 336 CASETYPE_TESS_LEVEL_OUTER0_TES, 337 CASETYPE_TESS_LEVEL_OUTER1_TES, 338 CASETYPE_TESS_LEVEL_OUTER2_TES, 339 CASETYPE_TESS_LEVEL_OUTER3_TES, 340 }; 341 342 enum Constants 343 { 344 OUTPUT_PATCH_SIZE = 5, 345 INPUT_PATCH_SIZE = 10, 346 }; 347 348 struct CaseDefinition 349 { 350 CaseType caseType; 351 std::string caseName; 352 bool usesReferenceImageFromFile; 353 std::string referenceImagePath; 354 std::string caseDescription; 355 }; 356 357 int getNumPrimitives (const CaseType type) 358 { 359 return (type == CASETYPE_PRIMITIVE_ID_TCS || type == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1); 360 } 361 362 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef) 363 { 364 // Vertex shader 365 { 366 std::ostringstream src; 367 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 368 << "\n" 369 << "layout(location = 0) in highp float in_v_attr;\n" 370 << "layout(location = 0) out highp float in_tc_attr;\n" 371 << "\n" 372 << "void main (void)\n" 373 << "{\n" 374 << " in_tc_attr = in_v_attr;\n" 375 << "}\n"; 376 377 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 378 } 379 380 // Tessellation control shader 381 { 382 std::ostringstream src; 383 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 384 << "#extension GL_EXT_tessellation_shader : require\n" 385 << "\n" 386 << "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n" 387 << "\n" 388 << "layout(location = 0) in highp float in_tc_attr[];\n" 389 << "layout(location = 0) out highp float in_te_attr[];\n" 390 << "\n" 391 << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ? "layout(location = 1) patch out mediump int in_te_primitiveIDFromTCS;\n" : 392 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch out mediump int in_te_patchVerticesInFromTCS;\n" : "") 393 << "\n" 394 << "void main (void)\n" 395 << "{\n" 396 << " in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n" 397 << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ? " in_te_primitiveIDFromTCS = gl_PrimitiveID;\n" : 398 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? " in_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n" : "") 399 << "\n" 400 << " gl_TessLevelInner[0] = 9.0;\n" 401 << " gl_TessLevelInner[1] = 8.0;\n" 402 << "\n" 403 << " gl_TessLevelOuter[0] = 7.0;\n" 404 << " gl_TessLevelOuter[1] = 6.0;\n" 405 << " gl_TessLevelOuter[2] = 5.0;\n" 406 << " gl_TessLevelOuter[3] = 4.0;\n" 407 << "}\n"; 408 409 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 410 } 411 412 // Tessellation evaluation shader 413 { 414 const float xScale = 1.0f / static_cast<float>(getNumPrimitives(caseDef.caseType)); 415 416 std::ostringstream src; 417 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 418 << "#extension GL_EXT_tessellation_shader : require\n" 419 << "\n" 420 << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n" 421 << "\n" 422 << "layout(location = 0) in highp float in_te_attr[];\n" 423 << "layout(location = 0) out mediump vec4 in_f_color;\n" 424 << "\n" 425 << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ? "layout(location = 1) patch in mediump int in_te_primitiveIDFromTCS;\n" : 426 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch in mediump int in_te_patchVerticesInFromTCS;\n" : "") 427 << "\n" 428 << "void main (void)\n" 429 << "{\n" 430 << " highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n" 431 << " highp float y = gl_TessCoord.y*2.0 - 1.0;\n" 432 << " gl_Position = vec4(x, y, 0.0, 1.0);\n" 433 << (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS ? " bool ok = in_te_primitiveIDFromTCS == 3;\n" : 434 caseDef.caseType == CASETYPE_PRIMITIVE_ID_TES ? " bool ok = gl_PrimitiveID == 3;\n" : 435 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? " bool ok = in_te_patchVerticesInFromTCS == " + de::toString(INPUT_PATCH_SIZE) + ";\n" : 436 caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TES ? " bool ok = gl_PatchVerticesIn == " + de::toString(OUTPUT_PATCH_SIZE) + ";\n" : 437 caseDef.caseType == CASETYPE_TESS_LEVEL_INNER0_TES ? " bool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n" : 438 caseDef.caseType == CASETYPE_TESS_LEVEL_INNER1_TES ? " bool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n" : 439 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER0_TES ? " bool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n" : 440 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER1_TES ? " bool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n" : 441 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER2_TES ? " bool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n" : 442 caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER3_TES ? " bool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n" : "") 443 << " in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n" 444 << "}\n"; 445 446 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 447 } 448 449 // Fragment shader 450 { 451 std::ostringstream src; 452 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 453 << "\n" 454 << "layout(location = 0) in mediump vec4 in_f_color;\n" 455 << "layout(location = 0) out mediump vec4 o_color;\n" 456 << "\n" 457 << "void main (void)\n" 458 << "{\n" 459 << " o_color = in_f_color;\n" 460 << "}\n"; 461 462 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 463 } 464 } 465 466 //! Resize an image and fill with white color. 467 void initializeWhiteReferenceImage (tcu::TextureLevel& image, const int width, const int height) 468 { 469 DE_ASSERT(width > 0 && height > 0); 470 471 image.setStorage(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), width, height); 472 tcu::PixelBufferAccess access = image.getAccess(); 473 474 const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f); 475 476 for (int y = 0; y < height; ++y) 477 for (int x = 0; x < width; ++x) 478 access.setPixel(white, x, y); 479 } 480 481 tcu::TestStatus test (Context& context, const CaseDefinition caseDef) 482 { 483 DE_ASSERT(!caseDef.usesReferenceImageFromFile || !caseDef.referenceImagePath.empty()); 484 485 // Input vertex attribute data 486 const int numPrimitives = getNumPrimitives(caseDef.caseType); 487 std::vector<float> vertexData (INPUT_PATCH_SIZE * numPrimitives, 0.0f); 488 const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size(); 489 490 for (int i = 0; i < numPrimitives; ++i) 491 vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives); 492 493 tcu::TextureLevel referenceImage; 494 if (caseDef.usesReferenceImageFromFile) 495 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str()); 496 else 497 initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE); 498 499 return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE, 500 VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess()); 501 } 502 503 } // PerPatchData ns 504 505 namespace GLPosition 506 { 507 508 enum CaseType 509 { 510 CASETYPE_VS_TO_TCS = 0, 511 CASETYPE_TCS_TO_TES, 512 CASETYPE_VS_TO_TCS_TO_TES, 513 }; 514 515 void initPrograms (vk::SourceCollections& programCollection, const CaseType caseType) 516 { 517 const bool vsToTCS = caseType == CASETYPE_VS_TO_TCS || caseType == CASETYPE_VS_TO_TCS_TO_TES; 518 const bool tcsToTES = caseType == CASETYPE_TCS_TO_TES || caseType == CASETYPE_VS_TO_TCS_TO_TES; 519 520 // Vertex shader 521 { 522 std::ostringstream src; 523 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 524 << "\n" 525 << "layout(location = 0) in highp vec4 in_v_attr;\n" 526 << (!vsToTCS ? "layout(location = 0) out highp vec4 in_tc_attr;\n" : "") 527 << "\n" 528 << "void main (void)\n" 529 << "{\n" 530 << " " << (vsToTCS ? "gl_Position" : "in_tc_attr") << " = in_v_attr;\n" 531 << "}\n"; 532 533 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 534 } 535 536 // Tessellation control shader 537 { 538 std::ostringstream src; 539 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 540 << "#extension GL_EXT_tessellation_shader : require\n" 541 << "\n" 542 << "layout(vertices = 3) out;\n" 543 << "\n" 544 << (!vsToTCS ? "layout(location = 0) in highp vec4 in_tc_attr[];\n" : "") 545 << (!tcsToTES ? "layout(location = 0) out highp vec4 in_te_attr[];\n" : "") 546 << "\n" 547 << "void main (void)\n" 548 << "{\n" 549 << " " << (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") << " = " 550 << (vsToTCS ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") << ";\n" 551 << "\n" 552 << " gl_TessLevelInner[0] = 2.0;\n" 553 << " gl_TessLevelInner[1] = 3.0;\n" 554 << "\n" 555 << " gl_TessLevelOuter[0] = 4.0;\n" 556 << " gl_TessLevelOuter[1] = 5.0;\n" 557 << " gl_TessLevelOuter[2] = 6.0;\n" 558 << " gl_TessLevelOuter[3] = 7.0;\n" 559 << "}\n"; 560 561 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 562 } 563 564 // Tessellation evaluation shader 565 { 566 const std::string tesIn0 = tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]"; 567 const std::string tesIn1 = tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]"; 568 const std::string tesIn2 = tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]"; 569 570 std::ostringstream src; 571 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 572 << "#extension GL_EXT_tessellation_shader : require\n" 573 << "\n" 574 << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_TRIANGLES) << ") in;\n" 575 << "\n" 576 << (!tcsToTES ? "layout(location = 0) in highp vec4 in_te_attr[];\n" : "") 577 << "layout(location = 0) out highp vec4 in_f_color;\n" 578 << "\n" 579 << "void main (void)\n" 580 << "{\n" 581 << " highp vec2 xy = gl_TessCoord.x * " << tesIn0 << ".xy\n" 582 << " + gl_TessCoord.y * " << tesIn1 << ".xy\n" 583 << " + gl_TessCoord.z * " << tesIn2 << ".xy;\n" 584 << " gl_Position = vec4(xy, 0.0, 1.0);\n" 585 << " in_f_color = vec4(" << tesIn0 << ".z + " << tesIn1 << ".w,\n" 586 << " " << tesIn2 << ".z + " << tesIn0 << ".w,\n" 587 << " " << tesIn1 << ".z + " << tesIn2 << ".w,\n" 588 << " 1.0);\n" 589 << "}\n"; 590 591 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 592 } 593 594 // Fragment shader 595 { 596 std::ostringstream src; 597 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 598 << "\n" 599 << "layout(location = 0) in highp vec4 in_f_color;\n" 600 << "layout(location = 0) out mediump vec4 o_color;\n" 601 << "\n" 602 << "void main (void)\n" 603 << "{\n" 604 << " o_color = in_f_color;\n" 605 << "}\n"; 606 607 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 608 } 609 } 610 611 tcu::TestStatus test (Context& context, const CaseType caseType) 612 { 613 DE_UNREF(caseType); 614 615 // Input vertex attribute data 616 static const float vertexData[3*4] = 617 { 618 -0.8f, -0.7f, 0.1f, 0.7f, 619 -0.5f, 0.4f, 0.2f, 0.5f, 620 0.3f, 0.2f, 0.3f, 0.45f 621 }; 622 623 tcu::TextureLevel referenceImage; 624 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/gl_position_ref.png"); 625 626 const int numPrimitives = 1; 627 const int inPatchSize = 3; 628 const int outPatchSize = 3; 629 630 return runTest(context, numPrimitives, inPatchSize, outPatchSize, 631 VK_FORMAT_R32G32B32A32_SFLOAT, vertexData, sizeof(vertexData), referenceImage.getAccess()); 632 } 633 634 } // GLPosition ns 635 636 namespace Barrier 637 { 638 639 enum Constants 640 { 641 NUM_VERTICES = 32, 642 }; 643 644 void initPrograms (vk::SourceCollections& programCollection) 645 { 646 // Vertex shader 647 { 648 std::ostringstream src; 649 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 650 << "\n" 651 << "layout(location = 0) in highp float in_v_attr;\n" 652 << "layout(location = 0) out highp float in_tc_attr;\n" 653 << "\n" 654 << "void main (void)\n" 655 << "{\n" 656 << " in_tc_attr = in_v_attr;\n" 657 << "}\n"; 658 659 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 660 } 661 662 // Tessellation control shader 663 { 664 std::ostringstream src; 665 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 666 << "#extension GL_EXT_tessellation_shader : require\n" 667 << "\n" 668 << "layout(vertices = " << NUM_VERTICES << ") out;\n" 669 << "\n" 670 << "layout(location = 0) in highp float in_tc_attr[];\n" 671 << "layout(location = 0) out highp float in_te_attr[];\n" 672 << "\n" 673 << "layout(location = 1) patch out highp float in_te_patchAttr;\n" 674 << "\n" 675 << "void main (void)\n" 676 << "{\n" 677 << " in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n" 678 << " in_te_patchAttr = 0.0f;\n" 679 << "\n" 680 << " barrier();\n" 681 << "\n" 682 << " if (gl_InvocationID == 5)\n" 683 << " in_te_patchAttr = float(gl_InvocationID)*0.1;\n" 684 << "\n" 685 << " barrier();\n" 686 << "\n" 687 << " highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n" 688 << "\n" 689 << " barrier();\n" 690 << "\n" 691 << " if (gl_InvocationID == " << NUM_VERTICES << "-1)\n" 692 << " in_te_patchAttr = float(gl_InvocationID);\n" 693 << "\n" 694 << " barrier();\n" 695 << "\n" 696 << " in_te_attr[gl_InvocationID] = temp;\n" 697 << "\n" 698 << " barrier();\n" 699 << "\n" 700 << " temp = temp + in_te_attr[(gl_InvocationID+1) % " << NUM_VERTICES << "];\n" 701 << "\n" 702 << " barrier();\n" 703 << "\n" 704 << " in_te_attr[gl_InvocationID] = 0.25*temp;\n" 705 << "\n" 706 << " gl_TessLevelInner[0] = 32.0;\n" 707 << " gl_TessLevelInner[1] = 32.0;\n" 708 << "\n" 709 << " gl_TessLevelOuter[0] = 32.0;\n" 710 << " gl_TessLevelOuter[1] = 32.0;\n" 711 << " gl_TessLevelOuter[2] = 32.0;\n" 712 << " gl_TessLevelOuter[3] = 32.0;\n" 713 << "}\n"; 714 715 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 716 } 717 718 // Tessellation evaluation shader 719 { 720 std::ostringstream src; 721 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 722 << "#extension GL_EXT_tessellation_shader : require\n" 723 << "\n" 724 << "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n" 725 << "\n" 726 << "layout(location = 0) in highp float in_te_attr[];\n" 727 << "layout(location = 1) patch in highp float in_te_patchAttr;\n" 728 << "\n" 729 << "layout(location = 0) out highp float in_f_blue;\n" 730 << "\n" 731 << "void main (void)\n" 732 << "{\n" 733 << " highp float x = gl_TessCoord.x*2.0 - 1.0;\n" 734 << " highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << NUM_VERTICES << "-1)))];\n" 735 << " gl_Position = vec4(x, y, 0.0, 1.0);\n" 736 << " in_f_blue = abs(in_te_patchAttr - float(" << NUM_VERTICES << "-1));\n" 737 << "}\n"; 738 739 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 740 } 741 742 // Fragment shader 743 { 744 std::ostringstream src; 745 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 746 << "\n" 747 << "layout(location = 0) in highp float in_f_blue;\n" 748 << "layout(location = 0) out mediump vec4 o_color;\n" 749 << "\n" 750 << "void main (void)\n" 751 << "{\n" 752 << " o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n" 753 << "}\n"; 754 755 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 756 } 757 } 758 759 tcu::TestStatus test (Context& context) 760 { 761 // Input vertex attribute data 762 std::vector<float> vertexData (NUM_VERTICES); 763 const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size(); 764 765 for (int i = 0; i < NUM_VERTICES; ++i) 766 vertexData[i] = static_cast<float>(i) / (NUM_VERTICES - 1); 767 768 tcu::TextureLevel referenceImage; 769 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/barrier_ref.png"); 770 771 const int numPrimitives = 1; 772 const int inPatchSize = NUM_VERTICES; 773 const int outPatchSize = NUM_VERTICES; 774 775 return runTest(context, numPrimitives, inPatchSize, outPatchSize, 776 VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess()); 777 } 778 779 } // Barrier ns 780 781 } // anonymous 782 783 //! These tests correspond to dEQP-GLES31.functional.tessellation.shader_input_output.* 784 tcu::TestCaseGroup* createShaderInputOutputTests (tcu::TestContext& testCtx) 785 { 786 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs")); 787 788 // Patch vertex counts 789 { 790 static const struct 791 { 792 int inPatchSize; 793 int outPatchSize; 794 } patchVertexCountCases[] = 795 { 796 { 5, 10 }, 797 { 10, 5 } 798 }; 799 800 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++) 801 { 802 const int inSize = patchVertexCountCases[caseNdx].inPatchSize; 803 const int outSize = patchVertexCountCases[caseNdx].outPatchSize; 804 805 const std::string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out"; 806 const PatchVertexCount::CaseDefinition caseDef = 807 { 808 inSize, outSize, "vulkan/data/tessellation/" + caseName + "_ref.png" 809 }; 810 811 addFunctionCaseWithPrograms(group.get(), caseName, "Test input and output patch vertex counts", 812 PatchVertexCount::initPrograms, PatchVertexCount::test, caseDef); 813 } 814 } 815 816 // Per patch data 817 { 818 static const PerPatchData::CaseDefinition cases[] = 819 { 820 { PerPatchData::CASETYPE_PRIMITIVE_ID_TCS, "primitive_id_tcs", true, "vulkan/data/tessellation/primitive_id_tcs_ref.png", "Read gl_PrimitiveID in TCS and pass it as patch output to TES" }, 821 { PerPatchData::CASETYPE_PRIMITIVE_ID_TES, "primitive_id_tes", true, "vulkan/data/tessellation/primitive_id_tes_ref.png", "Read gl_PrimitiveID in TES" }, 822 { PerPatchData::CASETYPE_PATCH_VERTICES_IN_TCS, "patch_vertices_in_tcs", false, "", "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES" }, 823 { PerPatchData::CASETYPE_PATCH_VERTICES_IN_TES, "patch_vertices_in_tes", false, "", "Read gl_PatchVerticesIn in TES" }, 824 { PerPatchData::CASETYPE_TESS_LEVEL_INNER0_TES, "tess_level_inner_0_tes", false, "", "Read gl_TessLevelInner[0] in TES" }, 825 { PerPatchData::CASETYPE_TESS_LEVEL_INNER1_TES, "tess_level_inner_1_tes", false, "", "Read gl_TessLevelInner[1] in TES" }, 826 { PerPatchData::CASETYPE_TESS_LEVEL_OUTER0_TES, "tess_level_outer_0_tes", false, "", "Read gl_TessLevelOuter[0] in TES" }, 827 { PerPatchData::CASETYPE_TESS_LEVEL_OUTER1_TES, "tess_level_outer_1_tes", false, "", "Read gl_TessLevelOuter[1] in TES" }, 828 { PerPatchData::CASETYPE_TESS_LEVEL_OUTER2_TES, "tess_level_outer_2_tes", false, "", "Read gl_TessLevelOuter[2] in TES" }, 829 { PerPatchData::CASETYPE_TESS_LEVEL_OUTER3_TES, "tess_level_outer_3_tes", false, "", "Read gl_TessLevelOuter[3] in TES" }, 830 }; 831 832 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 833 addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, cases[caseNdx].caseDescription, 834 PerPatchData::initPrograms, PerPatchData::test, cases[caseNdx]); 835 } 836 837 // gl_Position 838 { 839 static const struct 840 { 841 GLPosition::CaseType type; 842 std::string caseName; 843 } cases[] = 844 { 845 { GLPosition::CASETYPE_VS_TO_TCS, "gl_position_vs_to_tcs" }, 846 { GLPosition::CASETYPE_TCS_TO_TES, "gl_position_tcs_to_tes" }, 847 { GLPosition::CASETYPE_VS_TO_TCS_TO_TES, "gl_position_vs_to_tcs_to_tes" }, 848 }; 849 850 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 851 addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, "Pass gl_Position between VS and TCS, or between TCS and TES", 852 GLPosition::initPrograms, GLPosition::test, cases[caseNdx].type); 853 } 854 855 // Barrier 856 addFunctionCaseWithPrograms(group.get(), "barrier", "Basic barrier usage", Barrier::initPrograms, Barrier::test); 857 858 return group.release(); 859 } 860 861 } // tessellation 862 } // vkt 863