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 Geometry Interaction - Passthrough 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktTessellationGeometryPassthroughTests.hpp" 26 #include "vktTestCaseUtil.hpp" 27 #include "vktTessellationUtil.hpp" 28 29 #include "tcuTestLog.hpp" 30 #include "tcuImageCompare.hpp" 31 32 #include "vkDefs.hpp" 33 #include "vkBarrierUtil.hpp" 34 #include "vkQueryUtil.hpp" 35 #include "vkBuilderUtil.hpp" 36 #include "vkTypeUtil.hpp" 37 #include "vkImageUtil.hpp" 38 #include "vkCmdUtil.hpp" 39 #include "vkObjUtil.hpp" 40 41 #include "deUniquePtr.hpp" 42 43 #include <string> 44 #include <vector> 45 46 namespace vkt 47 { 48 namespace tessellation 49 { 50 51 using namespace vk; 52 53 namespace 54 { 55 56 void addVertexAndFragmentShaders (vk::SourceCollections& programCollection) 57 { 58 // Vertex shader 59 { 60 std::ostringstream src; 61 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 62 << "\n" 63 << "layout(location = 0) in highp vec4 a_position;\n" 64 << "layout(location = 0) out highp vec4 v_vertex_color;\n" 65 << "\n" 66 << "void main (void)\n" 67 << "{\n" 68 << " gl_Position = a_position;\n" 69 << " v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n" 70 << "}\n"; 71 72 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 73 } 74 75 // Fragment shader 76 { 77 std::ostringstream src; 78 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 79 << "\n" 80 << "layout(location = 0) in highp vec4 v_fragment_color;\n" 81 << "layout(location = 0) out mediump vec4 fragColor;\n" 82 << "void main (void)\n" 83 << "{\n" 84 << " fragColor = v_fragment_color;\n" 85 << "}\n"; 86 87 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 88 } 89 } 90 91 //! Tessellation evaluation shader used in passthrough geometry shader case. 92 std::string generateTessellationEvaluationShader (const TessPrimitiveType primitiveType, const std::string& colorOutputName) 93 { 94 std::ostringstream src; 95 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 96 << "#extension GL_EXT_tessellation_shader : require\n" 97 << "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ") in;\n" 98 << "\n" 99 << "layout(location = 0) in highp vec4 v_patch_color[];\n" 100 << "layout(location = 0) out highp vec4 " << colorOutputName << ";\n" 101 << "\n" 102 << "// note: No need to use precise gl_Position since we do not require gapless geometry\n" 103 << "void main (void)\n" 104 << "{\n"; 105 106 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES) 107 src << " vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n" 108 << " vec3 cweights = gl_TessCoord;\n" 109 << " gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n" 110 << " " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n"; 111 else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES) 112 src << " vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n" 113 << " vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n" 114 << " vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n" 115 << " vec2 cweights = gl_TessCoord.xy;\n" 116 << " gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n" 117 << " " << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n"; 118 else 119 DE_ASSERT(false); 120 121 src << "}\n"; 122 123 return src.str(); 124 } 125 126 class IdentityGeometryShaderTestCase : public TestCase 127 { 128 public: 129 void initPrograms (vk::SourceCollections& programCollection) const; 130 TestInstance* createInstance (Context& context) const; 131 132 IdentityGeometryShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType) 133 : TestCase (testCtx, name, description) 134 , m_primitiveType (primitiveType) 135 { 136 } 137 138 private: 139 const TessPrimitiveType m_primitiveType; 140 }; 141 142 void IdentityGeometryShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const 143 { 144 addVertexAndFragmentShaders(programCollection); 145 146 // Tessellation control 147 { 148 std::ostringstream src; 149 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 150 << "#extension GL_EXT_tessellation_shader : require\n" 151 << "layout(vertices = 4) out;\n" 152 << "\n" 153 << "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n" 154 << " float inner0;\n" 155 << " float inner1;\n" 156 << " float outer0;\n" 157 << " float outer1;\n" 158 << " float outer2;\n" 159 << " float outer3;\n" 160 << "} sb_levels;\n" 161 << "\n" 162 << "layout(location = 0) in highp vec4 v_vertex_color[];\n" 163 << "layout(location = 0) out highp vec4 v_patch_color[];\n" 164 << "\n" 165 << "void main (void)\n" 166 << "{\n" 167 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 168 << " v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n" 169 << "\n" 170 << " gl_TessLevelInner[0] = sb_levels.inner0;\n" 171 << " gl_TessLevelInner[1] = sb_levels.inner1;\n" 172 << " gl_TessLevelOuter[0] = sb_levels.outer0;\n" 173 << " gl_TessLevelOuter[1] = sb_levels.outer1;\n" 174 << " gl_TessLevelOuter[2] = sb_levels.outer2;\n" 175 << " gl_TessLevelOuter[3] = sb_levels.outer3;\n" 176 << "}\n"; 177 178 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 179 } 180 181 // Tessellation evaluation shader 182 { 183 programCollection.glslSources.add("tese_to_frag") 184 << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_fragment_color")); 185 programCollection.glslSources.add("tese_to_geom") 186 << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_evaluated_color")); 187 } 188 189 // Geometry shader 190 { 191 std::ostringstream src; 192 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 193 << "#extension GL_EXT_geometry_shader : require\n" 194 << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(m_primitiveType, false) << ") in;\n" 195 << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(m_primitiveType, false) 196 << ", max_vertices=" << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n" 197 << "\n" 198 << "layout(location = 0) in highp vec4 v_evaluated_color[];\n" 199 << "layout(location = 0) out highp vec4 v_fragment_color;\n" 200 << "\n" 201 << "void main (void)\n" 202 << "{\n" 203 << " for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n" 204 << " {\n" 205 << " gl_Position = gl_in[ndx].gl_Position;\n" 206 << " v_fragment_color = v_evaluated_color[ndx];\n" 207 << " EmitVertex();\n" 208 << " }\n" 209 << "}\n"; 210 211 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); 212 } 213 } 214 215 class IdentityTessellationShaderTestCase : public TestCase 216 { 217 public: 218 void initPrograms (vk::SourceCollections& programCollection) const; 219 TestInstance* createInstance (Context& context) const; 220 221 IdentityTessellationShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType) 222 : TestCase (testCtx, name, description) 223 , m_primitiveType (primitiveType) 224 { 225 } 226 227 private: 228 const TessPrimitiveType m_primitiveType; 229 }; 230 231 //! Geometry shader used in passthrough tessellation shader case. 232 std::string generateGeometryShader (const TessPrimitiveType primitiveType, const std::string& colorSourceName) 233 { 234 const int numEmitVertices = (primitiveType == TESSPRIMITIVETYPE_ISOLINES ? 11 : 8); 235 236 std::ostringstream src; 237 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 238 << "#extension GL_EXT_geometry_shader : require\n" 239 << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, false) << ") in;\n" 240 << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, false) 241 << ", max_vertices=" << numEmitVertices << ") out;\n" 242 << "\n" 243 << "layout(location = 0) in highp vec4 " << colorSourceName << "[];\n" 244 << "layout(location = 0) out highp vec4 v_fragment_color;\n" 245 << "\n" 246 << "void main (void)\n" 247 << "{\n"; 248 249 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES) 250 { 251 src << " vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n" 252 << "\n" 253 << " for (int ndx = 0; ndx < 4; ++ndx)\n" 254 << " {\n" 255 << " gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n" 256 << " v_fragment_color = " << colorSourceName << "[ndx % 3];\n" 257 << " EmitVertex();\n" 258 << "\n" 259 << " gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n" 260 << " v_fragment_color = " << colorSourceName << "[ndx % 3];\n" 261 << " EmitVertex();\n" 262 << " }\n"; 263 } 264 else if (primitiveType == TESSPRIMITIVETYPE_ISOLINES) 265 { 266 src << " vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n" 267 << " for (int i = 0; i <= 10; ++i)\n" 268 << " {\n" 269 << " float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n" 270 << " float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n" 271 << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n" 272 << " v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n" 273 << " EmitVertex();\n" 274 << " }\n"; 275 } 276 else 277 DE_ASSERT(false); 278 279 src << "}\n"; 280 281 return src.str(); 282 } 283 284 void IdentityTessellationShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const 285 { 286 addVertexAndFragmentShaders(programCollection); 287 288 // Tessellation control 289 { 290 std::ostringstream src; 291 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 292 << "#extension GL_EXT_tessellation_shader : require\n" 293 << "layout(vertices = " << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n" 294 << "\n" 295 << "layout(location = 0) in highp vec4 v_vertex_color[];\n" 296 << "layout(location = 0) out highp vec4 v_control_color[];\n" 297 << "\n" 298 << "void main (void)\n" 299 << "{\n" 300 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 301 << " v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n" 302 << "\n" 303 << " gl_TessLevelInner[0] = 1.0;\n" 304 << " gl_TessLevelInner[1] = 1.0;\n" 305 << " gl_TessLevelOuter[0] = 1.0;\n" 306 << " gl_TessLevelOuter[1] = 1.0;\n" 307 << " gl_TessLevelOuter[2] = 1.0;\n" 308 << " gl_TessLevelOuter[3] = 1.0;\n" 309 << "}\n"; 310 311 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 312 } 313 314 // Tessellation evaluation shader 315 { 316 std::ostringstream src; 317 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n" 318 << "#extension GL_EXT_tessellation_shader : require\n" 319 << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ") in;\n" 320 << "\n" 321 << "layout(location = 0) in highp vec4 v_control_color[];\n" 322 << "layout(location = 0) out highp vec4 v_evaluated_color;\n" 323 << "\n" 324 << "// note: No need to use precise gl_Position since we do not require gapless geometry\n" 325 << "void main (void)\n" 326 << "{\n"; 327 328 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES) 329 src << " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n" 330 << " v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n"; 331 else if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES) 332 src << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n" 333 << " v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n"; 334 else 335 DE_ASSERT(false); 336 337 src << "}\n"; 338 339 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 340 } 341 342 // Geometry shader 343 { 344 programCollection.glslSources.add("geom_from_tese") << glu::GeometrySource( 345 generateGeometryShader(m_primitiveType, "v_evaluated_color")); 346 programCollection.glslSources.add("geom_from_vert") << glu::GeometrySource( 347 generateGeometryShader(m_primitiveType, "v_vertex_color")); 348 } 349 } 350 351 inline tcu::ConstPixelBufferAccess getPixelBufferAccess (const DeviceInterface& vk, 352 const VkDevice device, 353 const Buffer& colorBuffer, 354 const VkFormat colorFormat, 355 const VkDeviceSize colorBufferSizeBytes, 356 const tcu::IVec2& renderSize) 357 { 358 const Allocation& alloc = colorBuffer.getAllocation(); 359 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes); 360 return tcu::ConstPixelBufferAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr()); 361 } 362 363 //! When a test case disables tessellation stage and we need to derive a primitive type. 364 VkPrimitiveTopology getPrimitiveTopology (const TessPrimitiveType primitiveType) 365 { 366 switch (primitiveType) 367 { 368 case TESSPRIMITIVETYPE_TRIANGLES: 369 case TESSPRIMITIVETYPE_QUADS: 370 return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 371 372 case TESSPRIMITIVETYPE_ISOLINES: 373 return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; 374 375 default: 376 DE_ASSERT(false); 377 return VK_PRIMITIVE_TOPOLOGY_LAST; 378 } 379 } 380 381 enum Constants 382 { 383 PIPELINE_CASES = 2, 384 RENDER_SIZE = 256, 385 }; 386 387 class PassthroughTestInstance : public TestInstance 388 { 389 public: 390 struct PipelineDescription 391 { 392 bool useTessellation; 393 bool useGeometry; 394 std::string tessEvalShaderName; 395 std::string geomShaderName; 396 std::string description; 397 398 PipelineDescription (void) : useTessellation(), useGeometry() {} 399 }; 400 401 struct Params 402 { 403 bool useTessLevels; 404 TessLevels tessLevels; 405 TessPrimitiveType primitiveType; 406 int inputPatchVertices; 407 std::vector<tcu::Vec4> vertices; 408 PipelineDescription pipelineCases[PIPELINE_CASES]; //!< Each test case renders with two pipelines and compares results 409 std::string message; 410 411 Params (void) : useTessLevels(), tessLevels(), primitiveType(), inputPatchVertices() {} 412 }; 413 414 PassthroughTestInstance (Context& context, const Params& params) : TestInstance(context), m_params(params) {} 415 tcu::TestStatus iterate (void); 416 417 private: 418 const Params m_params; 419 }; 420 421 tcu::TestStatus PassthroughTestInstance::iterate (void) 422 { 423 requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER); 424 DE_STATIC_ASSERT(PIPELINE_CASES == 2); 425 426 const DeviceInterface& vk = m_context.getDeviceInterface(); 427 const VkDevice device = m_context.getDevice(); 428 const VkQueue queue = m_context.getUniversalQueue(); 429 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 430 Allocator& allocator = m_context.getDefaultAllocator(); 431 432 // Tessellation levels 433 const Buffer tessLevelsBuffer (vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 434 435 if (m_params.useTessLevels) 436 { 437 const Allocation& alloc = tessLevelsBuffer.getAllocation(); 438 TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr()); 439 *bufferTessLevels = m_params.tessLevels; 440 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels)); 441 } 442 443 // Vertex attributes 444 445 const VkDeviceSize vertexDataSizeBytes = sizeInBytes(m_params.vertices); 446 const VkFormat vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; 447 const Buffer vertexBuffer (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible); 448 449 { 450 const Allocation& alloc = vertexBuffer.getAllocation(); 451 deMemcpy(alloc.getHostPtr(), &m_params.vertices[0], static_cast<std::size_t>(vertexDataSizeBytes)); 452 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes); 453 } 454 455 // Descriptors - make descriptor for tessellation levels, even if we don't use them, to simplify code 456 457 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 458 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) 459 .build(vk, device)); 460 461 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 462 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 463 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 464 465 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 466 const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(*tessLevelsBuffer, 0ull, sizeof(TessLevels)); 467 468 DescriptorSetUpdateBuilder() 469 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo) 470 .update(vk, device); 471 472 // Color attachment 473 474 const tcu::IVec2 renderSize = tcu::IVec2(RENDER_SIZE, RENDER_SIZE); 475 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 476 const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 477 const Image colorAttachmentImage (vk, device, allocator, 478 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u), 479 MemoryRequirement::Any); 480 481 // Color output buffer: image will be copied here for verification. 482 // We use two buffers, one for each case. 483 484 const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)); 485 const Buffer colorBuffer1 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible); 486 const Buffer colorBuffer2 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible); 487 const Buffer* const colorBuffer[PIPELINE_CASES] = { &colorBuffer1, &colorBuffer2 }; 488 489 // Pipeline 490 491 const Unique<VkImageView> colorAttachmentView(makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange)); 492 const Unique<VkRenderPass> renderPass (makeRenderPass(vk, device, colorFormat)); 493 const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u)); 494 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); 495 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex)); 496 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 497 498 // Message explaining the test 499 { 500 tcu::TestLog& log = m_context.getTestContext().getLog(); 501 log << tcu::TestLog::Message << m_params.message << tcu::TestLog::EndMessage; 502 503 if (m_params.useTessLevels) 504 log << tcu::TestLog::Message << "Tessellation levels: " << getTessellationLevelsString(m_params.tessLevels, m_params.primitiveType) << tcu::TestLog::EndMessage; 505 } 506 507 for (int pipelineNdx = 0; pipelineNdx < PIPELINE_CASES; ++pipelineNdx) 508 { 509 const PipelineDescription& pipelineDescription = m_params.pipelineCases[pipelineNdx]; 510 GraphicsPipelineBuilder pipelineBuilder; 511 512 pipelineBuilder 513 .setPrimitiveTopology (getPrimitiveTopology(m_params.primitiveType)) 514 .setRenderSize (renderSize) 515 .setBlend (true) 516 .setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat))) 517 .setPatchControlPoints (m_params.inputPatchVertices) 518 .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), DE_NULL) 519 .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), DE_NULL); 520 521 if (pipelineDescription.useTessellation) 522 pipelineBuilder 523 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), DE_NULL) 524 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(pipelineDescription.tessEvalShaderName), DE_NULL); 525 526 if (pipelineDescription.useGeometry) 527 pipelineBuilder 528 .setShader (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get(pipelineDescription.geomShaderName), DE_NULL); 529 530 const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass)); 531 532 // Draw commands 533 534 beginCommandBuffer(vk, *cmdBuffer); 535 536 // Change color attachment image layout 537 { 538 // State is slightly different on the first iteration. 539 const VkImageLayout currentLayout = (pipelineNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); 540 const VkAccessFlags srcFlags = (pipelineNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT); 541 542 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier( 543 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 544 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 545 *colorAttachmentImage, colorImageSubresourceRange); 546 547 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 548 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier); 549 } 550 551 // Begin render pass 552 { 553 const VkRect2D renderArea = makeRect2D(renderSize); 554 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f); 555 556 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); 557 } 558 559 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 560 { 561 const VkDeviceSize vertexBufferOffset = 0ull; 562 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); 563 } 564 565 if (m_params.useTessLevels) 566 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 567 568 vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(m_params.vertices.size()), 1u, 0u, 0u); 569 endRenderPass(vk, *cmdBuffer); 570 571 // Copy render result to a host-visible buffer 572 copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, colorBuffer[pipelineNdx]->get(), renderSize); 573 574 endCommandBuffer(vk, *cmdBuffer); 575 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 576 } 577 578 // Verify results 579 580 tcu::ConstPixelBufferAccess image0 = getPixelBufferAccess(vk, device, *colorBuffer[0], colorFormat, colorBufferSizeBytes, renderSize); 581 tcu::ConstPixelBufferAccess image1 = getPixelBufferAccess(vk, device, *colorBuffer[1], colorFormat, colorBufferSizeBytes, renderSize); 582 583 const tcu::UVec4 colorThreshold (8, 8, 8, 255); 584 const tcu::IVec3 positionDeviation (1, 1, 0); // 3x3 search kernel 585 const bool ignoreOutOfBounds = true; 586 587 tcu::TestLog& log = m_context.getTestContext().getLog(); 588 log << tcu::TestLog::Message 589 << "In image comparison:\n" 590 << " Reference - " << m_params.pipelineCases[0].description << "\n" 591 << " Result - " << m_params.pipelineCases[1].description << "\n" 592 << tcu::TestLog::EndMessage; 593 594 const bool ok = tcu::intThresholdPositionDeviationCompare( 595 log, "ImageCompare", "Image comparison", image0, image1, colorThreshold, positionDeviation, ignoreOutOfBounds, tcu::COMPARE_LOG_RESULT); 596 597 return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed")); 598 } 599 600 TestInstance* IdentityGeometryShaderTestCase::createInstance (Context& context) const 601 { 602 PassthroughTestInstance::Params params; 603 604 const float level = 14.0; 605 params.useTessLevels = true; 606 params.tessLevels.inner[0] = level; 607 params.tessLevels.inner[1] = level; 608 params.tessLevels.outer[0] = level; 609 params.tessLevels.outer[1] = level; 610 params.tessLevels.outer[2] = level; 611 params.tessLevels.outer[3] = level; 612 613 params.primitiveType = m_primitiveType; 614 params.inputPatchVertices = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4); 615 616 params.vertices.push_back(tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f )); 617 params.vertices.push_back(tcu::Vec4( -0.9f, 0.9f, 0.0f, 1.0f )); 618 params.vertices.push_back(tcu::Vec4( 0.9f, -0.9f, 0.0f, 1.0f )); 619 params.vertices.push_back(tcu::Vec4( 0.9f, 0.9f, 0.0f, 1.0f )); 620 621 params.pipelineCases[0].useTessellation = true; 622 params.pipelineCases[0].useGeometry = true; 623 params.pipelineCases[0].tessEvalShaderName = "tese_to_geom"; 624 params.pipelineCases[0].geomShaderName = "geom"; 625 params.pipelineCases[0].description = "passthrough geometry shader"; 626 627 params.pipelineCases[1].useTessellation = true; 628 params.pipelineCases[1].useGeometry = false; 629 params.pipelineCases[1].tessEvalShaderName = "tese_to_frag"; 630 params.pipelineCases[1].geomShaderName = "geom"; 631 params.pipelineCases[1].description = "no geometry shader in the pipeline"; 632 633 params.message = "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n" 634 "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n" 635 "Using additive blending to detect overlap.\n"; 636 637 return new PassthroughTestInstance(context, params); 638 }; 639 640 TestInstance* IdentityTessellationShaderTestCase::createInstance (Context& context) const 641 { 642 PassthroughTestInstance::Params params; 643 644 params.useTessLevels = false; 645 params.primitiveType = m_primitiveType; 646 params.inputPatchVertices = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2); 647 648 params.vertices.push_back( tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f )); 649 params.vertices.push_back( tcu::Vec4( 0.0f, -0.5f, 0.0f, 1.0f )); 650 if (params.inputPatchVertices == 3) 651 params.vertices.push_back(tcu::Vec4( 0.4f, 0.4f, 0.0f, 1.0f )); 652 653 params.pipelineCases[0].useTessellation = true; 654 params.pipelineCases[0].useGeometry = true; 655 params.pipelineCases[0].tessEvalShaderName = "tese"; 656 params.pipelineCases[0].geomShaderName = "geom_from_tese"; 657 params.pipelineCases[0].description = "passthrough tessellation shaders"; 658 659 params.pipelineCases[1].useTessellation = false; 660 params.pipelineCases[1].useGeometry = true; 661 params.pipelineCases[1].tessEvalShaderName = "tese"; 662 params.pipelineCases[1].geomShaderName = "geom_from_vert"; 663 params.pipelineCases[1].description = "no tessellation shaders in the pipeline"; 664 665 params.message = "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n" 666 "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n" 667 "Using additive blending to detect overlap.\n"; 668 669 return new PassthroughTestInstance(context, params); 670 }; 671 672 inline TestCase* makeIdentityGeometryShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType) 673 { 674 return new IdentityGeometryShaderTestCase( 675 testCtx, 676 "tessellate_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_passthrough_geometry_no_change", 677 "Passthrough geometry shader has no effect", 678 primitiveType); 679 } 680 681 inline TestCase* makeIdentityTessellationShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType) 682 { 683 return new IdentityTessellationShaderTestCase( 684 testCtx, 685 "passthrough_tessellation_geometry_shade_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_no_change", 686 "Passthrough tessellation shader has no effect", 687 primitiveType); 688 } 689 690 } // anonymous 691 692 693 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.passthrough.* 694 tcu::TestCaseGroup* createGeometryPassthroughTests (tcu::TestContext& testCtx) 695 { 696 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "passthrough", "Render various types with either passthrough geometry or tessellation shader")); 697 698 // Passthrough geometry shader 699 group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES)); 700 group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_QUADS)); 701 group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES)); 702 703 // Passthrough tessellation shader 704 group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES)); 705 group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES)); 706 707 return group.release(); 708 } 709 710 } // tessellation 711 } // vkt 712