1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Pipeline specialization constants tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktPipelineSpecConstantTests.hpp" 25 #include "vktTestCase.hpp" 26 #include "vktPipelineSpecConstantUtil.hpp" 27 #include "vktPipelineMakeUtil.hpp" 28 29 #include "tcuTestLog.hpp" 30 #include "tcuTexture.hpp" 31 #include "tcuFormatUtil.hpp" 32 33 #include "gluShaderUtil.hpp" 34 35 #include "vkBuilderUtil.hpp" 36 #include "vkPrograms.hpp" 37 #include "vkRefUtil.hpp" 38 #include "vkTypeUtil.hpp" 39 #include "vkImageUtil.hpp" 40 41 #include "deUniquePtr.hpp" 42 #include "deStringUtil.hpp" 43 44 namespace vkt 45 { 46 namespace pipeline 47 { 48 49 using namespace vk; 50 51 namespace 52 { 53 54 static const char* const s_perVertexBlock = "gl_PerVertex {\n" 55 " vec4 gl_Position;\n" 56 "}"; 57 58 //! Raw memory storage for values used in test cases. 59 //! We use it to simplify test case definitions where different types are expected in the result. 60 class GenericValue 61 { 62 public: 63 GenericValue (void) { clear(); } 64 65 //! Copy up to 'size' bytes of 'data'. 66 GenericValue (const void* data, const deUint32 size) 67 { 68 DE_ASSERT(size <= sizeof(m_data)); 69 clear(); 70 deMemcpy(&m_data, data, size); 71 } 72 73 private: 74 deUint64 m_data; 75 76 void clear (void) { m_data = 0; } 77 }; 78 79 inline GenericValue makeValueBool32 (const bool a) { return GenericValue(&a, sizeof(a)); } 80 inline GenericValue makeValueInt32 (const deInt32 a) { return GenericValue(&a, sizeof(a)); } 81 // \note deInt64 not tested 82 inline GenericValue makeValueUint32 (const deUint32 a) { return GenericValue(&a, sizeof(a)); } 83 // \note deUint64 not tested 84 inline GenericValue makeValueFloat32 (const float a) { return GenericValue(&a, sizeof(a)); } 85 inline GenericValue makeValueFloat64 (const double a) { return GenericValue(&a, sizeof(a)); } 86 87 struct SpecConstant 88 { 89 deUint32 specID; //!< specialization constant ID 90 std::string declarationCode; //!< syntax to declare the constant, use ${ID} as an ID placeholder 91 deUint32 size; //!< data size on the host, 0 = no specialized value 92 GenericValue specValue; //!< specialized value passed by the API 93 94 SpecConstant (const deUint32 specID_, const std::string declarationCode_) 95 : specID (specID_) 96 , declarationCode (declarationCode_) 97 , size (0) 98 , specValue () 99 { 100 } 101 102 SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_) 103 : specID (specID_) 104 , declarationCode (declarationCode_) 105 , size (size_) 106 , specValue (specValue_) 107 { 108 } 109 }; 110 111 //! Useful when referring to a value in a buffer (i.e. check expected values in SSBO). 112 struct OffsetValue 113 { 114 deUint32 size; //!< data size in the buffer (up to sizeof(value)) 115 deUint32 offset; //!< offset into the buffer 116 GenericValue value; //!< value expected to be there 117 118 OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_) 119 : size (size_) 120 , offset (offset_) 121 , value (value_) 122 {} 123 }; 124 125 //! Get the integer value of 'size' bytes at 'memory' location. 126 deUint64 memoryAsInteger (const void* memory, const deUint32 size) 127 { 128 DE_ASSERT(size <= sizeof(deUint64)); 129 deUint64 value = 0; 130 deMemcpy(&value, memory, size); 131 return value; 132 } 133 134 inline std::string memoryAsHexString (const void* memory, const deUint32 size) 135 { 136 const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory); 137 return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size))); 138 } 139 140 void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size) 141 { 142 const bool canDisplayValue = (size <= sizeof(deUint64)); 143 log << tcu::TestLog::Message 144 << "Comparison failed for value at offset " << de::toString(offset) << ": expected " 145 << (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got " 146 << (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size) 147 << tcu::TestLog::EndMessage; 148 } 149 150 //! Check if expected values exist in the memory. 151 bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues) 152 { 153 bool ok = true; 154 log << tcu::TestLog::Section("compare", "Verify result values"); 155 156 for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it) 157 { 158 const char* const valuePtr = static_cast<const char*>(memory) + it->offset; 159 if (deMemCmp(valuePtr, &it->value, it->size) != 0) 160 { 161 ok = false; 162 logValueMismatch(log, &it->value, valuePtr, it->offset, it->size); 163 } 164 } 165 166 if (ok) 167 log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage; 168 169 log << tcu::TestLog::EndSection; 170 return ok; 171 } 172 173 //! Bundles together common test case parameters. 174 struct CaseDefinition 175 { 176 std::string name; //!< Test case name 177 std::vector<SpecConstant> specConstants; //!< list of specialization constants to declare 178 VkDeviceSize ssboSize; //!< required ssbo size in bytes 179 std::string ssboCode; //!< ssbo member definitions 180 std::string globalCode; //!< generic shader code outside the main function (e.g. declarations) 181 std::string mainCode; //!< generic shader code to execute in main (e.g. assignments) 182 std::vector<OffsetValue> expectedValues; //!< list of values to check inside the ssbo buffer 183 FeatureFlags requirements; //!< features the implementation must support to allow this test to run 184 }; 185 186 //! Manages Vulkan structures to pass specialization data. 187 class Specialization 188 { 189 public: 190 Specialization (const std::vector<SpecConstant>& specConstants); 191 192 //! Can return NULL if nothing is specialized 193 const VkSpecializationInfo* getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; } 194 195 private: 196 std::vector<GenericValue> m_data; 197 std::vector<VkSpecializationMapEntry> m_entries; 198 VkSpecializationInfo m_specialization; 199 }; 200 201 Specialization::Specialization (const std::vector<SpecConstant>& specConstants) 202 { 203 m_data.reserve(specConstants.size()); 204 m_entries.reserve(specConstants.size()); 205 206 deUint32 offset = 0; 207 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it) 208 if (it->size != 0) 209 { 210 m_data.push_back(it->specValue); 211 m_entries.push_back(makeSpecializationMapEntry(it->specID, offset, it->size)); 212 offset += (deUint32)sizeof(GenericValue); 213 } 214 215 if (m_entries.size() > 0) 216 { 217 m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size()); 218 m_specialization.pMapEntries = &m_entries[0]; 219 m_specialization.dataSize = sizeof(GenericValue) * m_data.size(); 220 m_specialization.pData = &m_data[0]; 221 } 222 else 223 deMemset(&m_specialization, 0, sizeof(m_specialization)); 224 } 225 226 class SpecConstantTest : public TestCase 227 { 228 public: 229 SpecConstantTest (tcu::TestContext& testCtx, 230 const VkShaderStageFlagBits stage, //!< which shader stage is tested 231 const CaseDefinition& caseDef); 232 233 void initPrograms (SourceCollections& programCollection) const; 234 TestInstance* createInstance (Context& context) const; 235 236 private: 237 const VkShaderStageFlagBits m_stage; 238 const CaseDefinition m_caseDef; 239 }; 240 241 SpecConstantTest::SpecConstantTest (tcu::TestContext& testCtx, 242 const VkShaderStageFlagBits stage, 243 const CaseDefinition& caseDef) 244 : TestCase (testCtx, caseDef.name, "") 245 , m_stage (stage) 246 , m_caseDef (caseDef) 247 { 248 } 249 250 //! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers. 251 std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants) 252 { 253 std::ostringstream code; 254 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it) 255 { 256 std::string decl = it->declarationCode; 257 const std::string::size_type pos = decl.find("${ID}"); 258 if (pos != std::string::npos) 259 decl.replace(pos, 5, de::toString(it->specID)); 260 code << decl << "\n"; 261 } 262 code << "\n"; 263 return code.str(); 264 } 265 266 std::string generateSSBOCode (const std::string& memberDeclarations) 267 { 268 std::ostringstream code; 269 code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n" 270 << memberDeclarations 271 << "} sb_out;\n" 272 << "\n"; 273 return code.str(); 274 } 275 276 void SpecConstantTest::initPrograms (SourceCollections& programCollection) const 277 { 278 // Always add vertex and fragment to graphics stages 279 VkShaderStageFlags requiredStages = m_stage; 280 281 if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) 282 requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; 283 284 if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) 285 requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; 286 287 // Either graphics or compute must be defined, but not both 288 DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0)); 289 290 if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT) 291 { 292 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT); 293 std::ostringstream src; 294 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 295 << "layout(location = 0) in highp vec4 position;\n" 296 << "\n" 297 << "out " << s_perVertexBlock << ";\n" 298 << "\n" 299 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 300 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 301 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 302 << "void main (void)\n" 303 << "{\n" 304 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 305 << " gl_Position = position;\n" 306 << "}\n"; 307 308 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 309 } 310 311 if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT) 312 { 313 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT); 314 std::ostringstream src; 315 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 316 << "layout(location = 0) out highp vec4 fragColor;\n" 317 << "\n" 318 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 319 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 320 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 321 << "void main (void)\n" 322 << "{\n" 323 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 324 << " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" 325 << "}\n"; 326 327 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 328 } 329 330 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) 331 { 332 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); 333 std::ostringstream src; 334 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 335 << "layout(vertices = 3) out;\n" 336 << "\n" 337 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 338 << "\n" 339 << "out " << s_perVertexBlock << " gl_out[];\n" 340 << "\n" 341 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 342 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 343 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 344 << "void main (void)\n" 345 << "{\n" 346 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 347 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 348 << " if (gl_InvocationID == 0)\n" 349 << " {\n" 350 << " gl_TessLevelInner[0] = 3;\n" 351 << " gl_TessLevelOuter[0] = 2;\n" 352 << " gl_TessLevelOuter[1] = 2;\n" 353 << " gl_TessLevelOuter[2] = 2;\n" 354 << " }\n" 355 << "}\n"; 356 357 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 358 } 359 360 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) 361 { 362 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); 363 std::ostringstream src; 364 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 365 << "layout(triangles, equal_spacing, ccw) in;\n" 366 << "\n" 367 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 368 << "\n" 369 << "out " << s_perVertexBlock << ";\n" 370 << "\n" 371 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 372 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 373 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 374 << "void main (void)\n" 375 << "{\n" 376 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 377 << " vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n" 378 << " vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n" 379 << " vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n" 380 << " gl_Position = vec4(p0 + p1 + p2, 1.0);\n" 381 << "}\n"; 382 383 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 384 } 385 386 if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) 387 { 388 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT); 389 std::ostringstream src; 390 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 391 << "layout(triangles) in;\n" 392 << "layout(triangle_strip, max_vertices = 3) out;\n" 393 << "\n" 394 << "in " << s_perVertexBlock << " gl_in[];\n" 395 << "\n" 396 << "out " << s_perVertexBlock << ";\n" 397 << "\n" 398 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 399 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 400 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 401 << "void main (void)\n" 402 << "{\n" 403 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 404 << " gl_Position = gl_in[0].gl_Position;\n" 405 << " EmitVertex();\n" 406 << "\n" 407 << " gl_Position = gl_in[1].gl_Position;\n" 408 << " EmitVertex();\n" 409 << "\n" 410 << " gl_Position = gl_in[2].gl_Position;\n" 411 << " EmitVertex();\n" 412 << "\n" 413 << " EndPrimitive();\n" 414 << "}\n"; 415 416 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); 417 } 418 419 if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) 420 { 421 std::ostringstream src; 422 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 423 // Don't define work group size, use the default or specialization constants 424 << "\n" 425 << generateSpecConstantCode(m_caseDef.specConstants) 426 << generateSSBOCode(m_caseDef.ssboCode) 427 << m_caseDef.globalCode + "\n" 428 << "void main (void)\n" 429 << "{\n" 430 << m_caseDef.mainCode 431 << "}\n"; 432 433 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str()); 434 } 435 } 436 437 class ComputeTestInstance : public TestInstance 438 { 439 public: 440 ComputeTestInstance (Context& context, 441 const VkDeviceSize ssboSize, 442 const std::vector<SpecConstant>& specConstants, 443 const std::vector<OffsetValue>& expectedValues); 444 445 tcu::TestStatus iterate (void); 446 447 private: 448 const VkDeviceSize m_ssboSize; 449 const std::vector<SpecConstant> m_specConstants; 450 const std::vector<OffsetValue> m_expectedValues; 451 }; 452 453 ComputeTestInstance::ComputeTestInstance (Context& context, 454 const VkDeviceSize ssboSize, 455 const std::vector<SpecConstant>& specConstants, 456 const std::vector<OffsetValue>& expectedValues) 457 : TestInstance (context) 458 , m_ssboSize (ssboSize) 459 , m_specConstants (specConstants) 460 , m_expectedValues (expectedValues) 461 { 462 } 463 464 tcu::TestStatus ComputeTestInstance::iterate (void) 465 { 466 const DeviceInterface& vk = m_context.getDeviceInterface(); 467 const VkDevice device = m_context.getDevice(); 468 const VkQueue queue = m_context.getUniversalQueue(); 469 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 470 Allocator& allocator = m_context.getDefaultAllocator(); 471 472 // Descriptors 473 474 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 475 476 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 477 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) 478 .build(vk, device)); 479 480 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 481 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 482 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 483 484 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 485 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize); 486 487 DescriptorSetUpdateBuilder() 488 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo) 489 .update(vk, device); 490 491 // Specialization 492 493 const Specialization specialization (m_specConstants); 494 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo(); 495 496 // Pipeline 497 498 const Unique<VkShaderModule> shaderModule (createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0)); 499 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout)); 500 const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, pSpecInfo)); 501 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); 502 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 503 504 beginCommandBuffer(vk, *cmdBuffer); 505 506 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); 507 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 508 509 vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u); 510 511 { 512 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier( 513 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize); 514 515 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 516 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL); 517 } 518 519 VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); 520 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 521 522 // Verify results 523 524 const Allocation& resultAlloc = resultBuffer.getAllocation(); 525 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize); 526 527 if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues)) 528 return tcu::TestStatus::pass("Success"); 529 else 530 return tcu::TestStatus::fail("Values did not match"); 531 } 532 533 class GraphicsTestInstance : public TestInstance 534 { 535 public: 536 GraphicsTestInstance (Context& context, 537 const VkDeviceSize ssboSize, 538 const std::vector<SpecConstant>& specConstants, 539 const std::vector<OffsetValue>& expectedValues, 540 const VkShaderStageFlagBits stage); 541 542 tcu::TestStatus iterate (void); 543 544 private: 545 const VkDeviceSize m_ssboSize; 546 const std::vector<SpecConstant> m_specConstants; 547 const std::vector<OffsetValue> m_expectedValues; 548 const VkShaderStageFlagBits m_stage; 549 }; 550 551 GraphicsTestInstance::GraphicsTestInstance (Context& context, 552 const VkDeviceSize ssboSize, 553 const std::vector<SpecConstant>& specConstants, 554 const std::vector<OffsetValue>& expectedValues, 555 const VkShaderStageFlagBits stage) 556 : TestInstance (context) 557 , m_ssboSize (ssboSize) 558 , m_specConstants (specConstants) 559 , m_expectedValues (expectedValues) 560 , m_stage (stage) 561 { 562 } 563 564 tcu::TestStatus GraphicsTestInstance::iterate (void) 565 { 566 const DeviceInterface& vk = m_context.getDeviceInterface(); 567 const VkDevice device = m_context.getDevice(); 568 const VkQueue queue = m_context.getUniversalQueue(); 569 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 570 Allocator& allocator = m_context.getDefaultAllocator(); 571 572 // Color attachment 573 574 const tcu::IVec2 renderSize = tcu::IVec2(32, 32); 575 const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; 576 const Image colorImage (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any); 577 const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))); 578 579 // Vertex buffer 580 581 const deUint32 numVertices = 3; 582 const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices; 583 const Buffer vertexBuffer (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible); 584 585 { 586 const Allocation& alloc = vertexBuffer.getAllocation(); 587 tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr()); 588 589 pVertices[0] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f); 590 pVertices[1] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f); 591 pVertices[2] = tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f); 592 593 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexBufferSizeBytes); 594 // No barrier needed, flushed memory is automatically visible 595 } 596 597 // Descriptors 598 599 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 600 601 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 602 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS) 603 .build(vk, device)); 604 605 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 606 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 607 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 608 609 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 610 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize); 611 612 DescriptorSetUpdateBuilder() 613 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo) 614 .update(vk, device); 615 616 // Specialization 617 618 const Specialization specialization (m_specConstants); 619 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo(); 620 621 // Pipeline 622 623 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, imageFormat)); 624 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y()))); 625 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout)); 626 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); 627 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 628 629 GraphicsPipelineBuilder pipelineBuilder; 630 pipelineBuilder 631 .setRenderSize(renderSize) 632 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), pSpecInfo) 633 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), pSpecInfo); 634 635 if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) 636 pipelineBuilder 637 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), pSpecInfo) 638 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), pSpecInfo); 639 640 if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT) 641 pipelineBuilder 642 .setShader(vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get("geom"), pSpecInfo); 643 644 const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass)); 645 646 // Draw commands 647 648 const VkRect2D renderArea = { 649 makeOffset2D(0, 0), 650 makeExtent2D(renderSize.x(), renderSize.y()), 651 }; 652 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f); 653 const VkDeviceSize vertexBufferOffset = 0ull; 654 655 beginCommandBuffer(vk, *cmdBuffer); 656 657 { 658 const VkImageSubresourceRange imageFullSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); 659 const VkImageMemoryBarrier barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier( 660 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 661 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 662 *colorImage, imageFullSubresourceRange); 663 664 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 665 0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout); 666 } 667 668 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor); 669 670 vk.cmdBindPipeline (*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); 671 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 672 vk.cmdBindVertexBuffers (*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset); 673 674 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u); 675 vk.cmdEndRenderPass(*cmdBuffer); 676 677 { 678 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier( 679 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize); 680 681 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 682 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL); 683 } 684 685 VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); 686 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 687 688 // Verify results 689 690 const Allocation& resultAlloc = resultBuffer.getAllocation(); 691 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize); 692 693 if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues)) 694 return tcu::TestStatus::pass("Success"); 695 else 696 return tcu::TestStatus::fail("Values did not match"); 697 } 698 699 FeatureFlags getShaderStageRequirements (const VkShaderStageFlags stageFlags) 700 { 701 FeatureFlags features = (FeatureFlags)0; 702 703 if (((stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) || ((stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0)) 704 features |= FEATURE_TESSELLATION_SHADER; 705 706 if ((stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0) 707 features |= FEATURE_GEOMETRY_SHADER; 708 709 // All tests use SSBO writes to read back results. 710 if ((stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) 711 { 712 if ((stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0) 713 features |= FEATURE_FRAGMENT_STORES_AND_ATOMICS; 714 else 715 features |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS; 716 } 717 718 return features; 719 } 720 721 TestInstance* SpecConstantTest::createInstance (Context& context) const 722 { 723 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), m_caseDef.requirements | getShaderStageRequirements(m_stage)); 724 725 if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT) 726 return new ComputeTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues); 727 else 728 return new GraphicsTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_stage); 729 } 730 731 //! Declare specialization constants but use them with default values. 732 tcu::TestCaseGroup* createDefaultValueTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage) 733 { 734 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "default_value", "use default constant value")); 735 736 const CaseDefinition defs[] = 737 { 738 { 739 "bool", 740 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;"), 741 SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;")), 742 8, 743 " bool r0;\n" 744 " bool r1;\n", 745 "", 746 " sb_out.r0 = sc0;\n" 747 " sb_out.r1 = sc1;\n", 748 makeVector(OffsetValue(4, 0, makeValueBool32(true)), 749 OffsetValue(4, 4, makeValueBool32(false))), 750 (FeatureFlags)0, 751 }, 752 { 753 "int", 754 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;"), 755 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 17;")), 756 8, 757 " int r0;\n" 758 " int r1;\n", 759 "", 760 " sb_out.r0 = sc0;\n" 761 " sb_out.r1 = sc1;\n", 762 makeVector(OffsetValue(4, 0, makeValueInt32(-3)), 763 OffsetValue(4, 4, makeValueInt32(17))), 764 (FeatureFlags)0, 765 }, 766 { 767 "uint", 768 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;")), 769 4, 770 " uint r0;\n", 771 "", 772 " sb_out.r0 = sc0;\n", 773 makeVector(OffsetValue(4, 0, makeValueUint32(42u))), 774 (FeatureFlags)0, 775 }, 776 { 777 "float", 778 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;")), 779 4, 780 " float r0;\n", 781 "", 782 " sb_out.r0 = sc0;\n", 783 makeVector(OffsetValue(4, 0, makeValueFloat32(7.5f))), 784 (FeatureFlags)0, 785 }, 786 { 787 "double", 788 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;")), 789 8, 790 " double r0;\n", 791 "", 792 " sb_out.r0 = sc0;\n", 793 makeVector(OffsetValue(8, 0, makeValueFloat64(2.75))), 794 FEATURE_SHADER_FLOAT_64, 795 }, 796 }; 797 798 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx) 799 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx])); 800 801 return testGroup.release(); 802 } 803 804 //! Declare specialization constants and specify their values through API. 805 tcu::TestCaseGroup* createBasicSpecializationTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage) 806 { 807 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "basic", "specialize a constant")); 808 809 const CaseDefinition defs[] = 810 { 811 { 812 "bool", 813 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;", 4, makeValueBool32(true)), 814 SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;", 4, makeValueBool32(false)), 815 SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;", 4, makeValueBool32(false)), 816 SpecConstant(4u, "layout(constant_id = ${ID}) const bool sc3 = false;", 4, makeValueBool32(true))), 817 16, 818 " bool r0;\n" 819 " bool r1;\n" 820 " bool r2;\n" 821 " bool r3;\n", 822 "", 823 " sb_out.r0 = sc0;\n" 824 " sb_out.r1 = sc1;\n" 825 " sb_out.r2 = sc2;\n" 826 " sb_out.r3 = sc3;\n", 827 makeVector(OffsetValue(4, 0, makeValueBool32(true)), 828 OffsetValue(4, 4, makeValueBool32(false)), 829 OffsetValue(4, 8, makeValueBool32(false)), 830 OffsetValue(4, 12, makeValueBool32(true))), 831 (FeatureFlags)0, 832 }, 833 { 834 "int", 835 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;", 4, makeValueInt32(33)), 836 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 91;"), 837 SpecConstant(3u, "layout(constant_id = ${ID}) const int sc2 = 17;", 4, makeValueInt32(-15))), 838 12, 839 " int r0;\n" 840 " int r1;\n" 841 " int r2;\n", 842 "", 843 " sb_out.r0 = sc0;\n" 844 " sb_out.r1 = sc1;\n" 845 " sb_out.r2 = sc2;\n", 846 makeVector(OffsetValue(4, 0, makeValueInt32(33)), 847 OffsetValue(4, 4, makeValueInt32(91)), 848 OffsetValue(4, 8, makeValueInt32(-15))), 849 (FeatureFlags)0, 850 }, 851 { 852 "uint", 853 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;", 4, makeValueUint32(97u)), 854 SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 7u;")), 855 8, 856 " uint r0;\n" 857 " uint r1;\n", 858 "", 859 " sb_out.r0 = sc0;\n" 860 " sb_out.r1 = sc1;\n", 861 makeVector(OffsetValue(4, 0, makeValueUint32(97u)), 862 OffsetValue(4, 4, makeValueUint32(7u))), 863 (FeatureFlags)0, 864 }, 865 { 866 "float", 867 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueFloat32(15.75f)), 868 SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;")), 869 8, 870 " float r0;\n" 871 " float r1;\n", 872 "", 873 " sb_out.r0 = sc0;\n" 874 " sb_out.r1 = sc1;\n", 875 makeVector(OffsetValue(4, 0, makeValueFloat32(15.75f)), 876 OffsetValue(4, 4, makeValueFloat32(1.125f))), 877 (FeatureFlags)0, 878 }, 879 { 880 "double", 881 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueFloat64(22.5)), 882 SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;")), 883 16, 884 " double r0;\n" 885 " double r1;\n", 886 "", 887 " sb_out.r0 = sc0;\n" 888 " sb_out.r1 = sc1;\n", 889 makeVector(OffsetValue(8, 0, makeValueFloat64(22.5)), 890 OffsetValue(8, 8, makeValueFloat64(9.25))), 891 FEATURE_SHADER_FLOAT_64, 892 }, 893 }; 894 895 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx) 896 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx])); 897 898 return testGroup.release(); 899 } 900 901 //! Specify compute shader work group size through specialization constants. 902 tcu::TestCaseGroup* createWorkGroupSizeTests (tcu::TestContext& testCtx) 903 { 904 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "local_size", "work group size specialization")); 905 906 const deUint32 ssboSize = 16; 907 const std::string ssboDecl = 908 " uvec3 workGroupSize;\n" 909 " uint checksum;\n"; 910 const std::string globalDecl = "shared uint count;\n"; 911 const std::string mainCode = 912 " count = 0u;\n" 913 "\n" 914 " groupMemoryBarrier();\n" 915 " barrier();\n" 916 "\n" 917 " atomicAdd(count, 1u);\n" 918 "\n" 919 " groupMemoryBarrier();\n" 920 " barrier();\n" 921 "\n" 922 " sb_out.workGroupSize = gl_WorkGroupSize;\n" 923 " sb_out.checksum = count;\n"; 924 925 const CaseDefinition defs[] = 926 { 927 { 928 "x", 929 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(7u))), 930 ssboSize, ssboDecl, globalDecl, mainCode, 931 makeVector(OffsetValue(4, 0, makeValueUint32(7u)), 932 OffsetValue(4, 4, makeValueUint32(1u)), 933 OffsetValue(4, 8, makeValueUint32(1u)), 934 OffsetValue(4, 12, makeValueUint32(7u))), 935 (FeatureFlags)0, 936 }, 937 { 938 "y", 939 makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(5u))), 940 ssboSize, ssboDecl, globalDecl, mainCode, 941 makeVector(OffsetValue(4, 0, makeValueUint32(1u)), 942 OffsetValue(4, 4, makeValueUint32(5u)), 943 OffsetValue(4, 8, makeValueUint32(1u)), 944 OffsetValue(4, 12, makeValueUint32(5u))), 945 (FeatureFlags)0, 946 }, 947 { 948 "z", 949 makeVector(SpecConstant(1u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(3u))), 950 ssboSize, ssboDecl, globalDecl, mainCode, 951 makeVector(OffsetValue(4, 0, makeValueUint32(1u)), 952 OffsetValue(4, 4, makeValueUint32(1u)), 953 OffsetValue(4, 8, makeValueUint32(3u)), 954 OffsetValue(4, 12, makeValueUint32(3u))), 955 (FeatureFlags)0, 956 }, 957 { 958 "xy", 959 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(6u)), 960 SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(4u))), 961 ssboSize, ssboDecl, globalDecl, mainCode, 962 makeVector(OffsetValue(4, 0, makeValueUint32(6u)), 963 OffsetValue(4, 4, makeValueUint32(4u)), 964 OffsetValue(4, 8, makeValueUint32(1u)), 965 OffsetValue(4, 12, makeValueUint32(6u * 4u))), 966 (FeatureFlags)0, 967 }, 968 { 969 "xz", 970 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(3u)), 971 SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(9u))), 972 ssboSize, ssboDecl, globalDecl, mainCode, 973 makeVector(OffsetValue(4, 0, makeValueUint32(3u)), 974 OffsetValue(4, 4, makeValueUint32(1u)), 975 OffsetValue(4, 8, makeValueUint32(9u)), 976 OffsetValue(4, 12, makeValueUint32(3u * 9u))), 977 (FeatureFlags)0, 978 }, 979 { 980 "yz", 981 makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(2u)), 982 SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(5u))), 983 ssboSize, ssboDecl, globalDecl, mainCode, 984 makeVector(OffsetValue(4, 0, makeValueUint32(1u)), 985 OffsetValue(4, 4, makeValueUint32(2u)), 986 OffsetValue(4, 8, makeValueUint32(5u)), 987 OffsetValue(4, 12, makeValueUint32(2u * 5u))), 988 (FeatureFlags)0, 989 }, 990 { 991 "xyz", 992 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(3u)), 993 SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(5u)), 994 SpecConstant(3u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(7u))), 995 ssboSize, ssboDecl, globalDecl, mainCode, 996 makeVector(OffsetValue(4, 0, makeValueUint32(3u)), 997 OffsetValue(4, 4, makeValueUint32(5u)), 998 OffsetValue(4, 8, makeValueUint32(7u)), 999 OffsetValue(4, 12, makeValueUint32(3u * 5u * 7u))), 1000 (FeatureFlags)0, 1001 }, 1002 }; 1003 1004 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx) 1005 testGroup->addChild(new SpecConstantTest(testCtx, VK_SHADER_STAGE_COMPUTE_BIT, defs[defNdx])); 1006 1007 return testGroup.release(); 1008 } 1009 1010 //! Override a built-in variable with specialization constant value. 1011 tcu::TestCaseGroup* createBuiltInOverrideTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage) 1012 { 1013 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "builtin", "built-in override")); 1014 1015 const CaseDefinition defs[] = 1016 { 1017 { 1018 "default", 1019 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;")), 1020 4, 1021 " bool ok;\n", 1022 "", 1023 " sb_out.ok = (gl_MaxImageUnits >= 8);\n", // implementation defined, 8 is the minimum 1024 makeVector(OffsetValue(4, 0, makeValueBool32(true))), 1025 (FeatureFlags)0, 1026 }, 1027 { 1028 "specialized", 1029 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;", 4, makeValueInt32(12))), 1030 4, 1031 " int maxImageUnits;\n", 1032 "", 1033 " sb_out.maxImageUnits = gl_MaxImageUnits;\n", 1034 makeVector(OffsetValue(4, 0, makeValueInt32(12))), 1035 (FeatureFlags)0, 1036 }, 1037 }; 1038 1039 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx) 1040 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx])); 1041 1042 return testGroup.release(); 1043 } 1044 1045 //! Specialization constants used in expressions. 1046 tcu::TestCaseGroup* createExpressionTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage) 1047 { 1048 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "expression", "specialization constants usage in expressions")); 1049 1050 const CaseDefinition defs[] = 1051 { 1052 { 1053 "spec_const_expression", 1054 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 2;"), 1055 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 3;", 4, makeValueInt32(5))), 1056 4, 1057 " int result;\n", 1058 1059 "const int expr0 = sc0 + 1;\n" 1060 "const int expr1 = sc0 + sc1;\n", 1061 1062 " sb_out.result = expr0 + expr1;\n", 1063 makeVector(OffsetValue(4, 0, makeValueInt32(10))), 1064 (FeatureFlags)0, 1065 }, 1066 { 1067 "array_size", 1068 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"), 1069 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(3))), 1070 16, 1071 " int r0;\n" 1072 " int r1[3];\n", 1073 1074 "", 1075 1076 " int a0[sc0];\n" 1077 " int a1[sc1];\n" 1078 "\n" 1079 " for (int i = 0; i < sc0; ++i)\n" 1080 " a0[i] = sc0 - i;\n" 1081 " for (int i = 0; i < sc1; ++i)\n" 1082 " a1[i] = sc1 - i;\n" 1083 "\n" 1084 " sb_out.r0 = a0[0];\n" 1085 " for (int i = 0; i < sc1; ++i)\n" 1086 " sb_out.r1[i] = a1[i];\n", 1087 makeVector(OffsetValue(4, 0, makeValueInt32(1)), 1088 OffsetValue(4, 4, makeValueInt32(3)), 1089 OffsetValue(4, 8, makeValueInt32(2)), 1090 OffsetValue(4, 12, makeValueInt32(1))), 1091 (FeatureFlags)0, 1092 }, 1093 { 1094 "array_size_expression", 1095 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"), 1096 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))), 1097 8, 1098 " int r0;\n" 1099 " int r1;\n", 1100 1101 "", 1102 1103 " int a0[sc0 + 3];\n" 1104 " int a1[sc0 + sc1];\n" 1105 "\n" 1106 " const int size0 = sc0 + 3;\n" 1107 " const int size1 = sc0 + sc1;\n" 1108 "\n" 1109 " for (int i = 0; i < size0; ++i)\n" 1110 " a0[i] = 3 - i;\n" 1111 " for (int i = 0; i < size1; ++i)\n" 1112 " a1[i] = 5 - i;\n" 1113 "\n" 1114 " sb_out.r0 = a0[size0 - 1];\n" 1115 " sb_out.r1 = a1[size1 - 1];\n", 1116 makeVector(OffsetValue(4, 0, makeValueInt32(-2)), 1117 OffsetValue(4, 4, makeValueInt32(-4))), 1118 (FeatureFlags)0, 1119 }, 1120 { 1121 "array_size_spec_const_expression", 1122 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"), 1123 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))), 1124 8, 1125 " int r0;\n" 1126 " int r1;\n", 1127 1128 "", 1129 1130 " const int size0 = sc0 + 3;\n" 1131 " const int size1 = sc0 + sc1;\n" 1132 "\n" 1133 " int a0[size0];\n" 1134 " int a1[size1];\n" 1135 "\n" 1136 " for (int i = 0; i < size0; ++i)\n" 1137 " a0[i] = 3 - i;\n" 1138 " for (int i = 0; i < size1; ++i)\n" 1139 " a1[i] = 5 - i;\n" 1140 "\n" 1141 " sb_out.r0 = a0[size0 - 1];\n" 1142 " sb_out.r1 = a1[size1 - 1];\n", 1143 makeVector(OffsetValue(4, 0, makeValueInt32(-2)), 1144 OffsetValue(4, 4, makeValueInt32(-4))), 1145 (FeatureFlags)0, 1146 }, 1147 { 1148 "array_size_length", 1149 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"), 1150 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(4))), 1151 8, 1152 " int r0;\n" 1153 " int r1;\n", 1154 1155 "", 1156 1157 " int a0[sc0];\n" 1158 " int a1[sc1];\n" 1159 "\n" 1160 " sb_out.r0 = a0.length();\n" 1161 " sb_out.r1 = a1.length();\n", 1162 makeVector(OffsetValue(4, 0, makeValueInt32(1)), 1163 OffsetValue(4, 4, makeValueInt32(4))), 1164 (FeatureFlags)0, 1165 }, 1166 { 1167 "array_size_pass_to_function", 1168 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"), 1169 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 1;", 4, makeValueInt32(3))), 1170 4, 1171 " int result;\n", 1172 1173 "int sumArrays (int a0[sc0], int a1[sc1])\n" 1174 "{\n" 1175 " int sum = 0;\n" 1176 " for (int i = 0; (i < sc0) && (i < sc1); ++i)\n" 1177 " sum += a0[i] + a1[i];\n" 1178 " return sum;\n" 1179 "}\n", 1180 1181 " int a0[sc0];\n" 1182 " int a1[sc1];\n" 1183 "\n" 1184 " for (int i = 0; i < sc0; ++i)\n" 1185 " a0[i] = i + 1;\n" 1186 " for (int i = 0; i < sc1; ++i)\n" 1187 " a1[i] = i + 2;\n" 1188 "\n" 1189 " sb_out.result = sumArrays(a0, a1);\n", 1190 makeVector(OffsetValue(4, 0, makeValueInt32(15))), 1191 (FeatureFlags)0, 1192 }, 1193 }; 1194 1195 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx) 1196 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx])); 1197 1198 return testGroup.release(); 1199 } 1200 1201 //! Helper functions internal to make*CompositeCaseDefinition functions. 1202 namespace composite_case_internal 1203 { 1204 1205 //! Generate a string like this: "1, 2, sc0, 4" or "true, true, sc0" 1206 //! castToType = true is useful when type requires more initializer values than we are providing, e.g.: 1207 //! vec2(1), vec2(sc0), vec(3) 1208 std::string generateInitializerListWithSpecConstant (const glu::DataType type, 1209 const bool castToType, 1210 const int idxBegin, 1211 const int idxEnd, 1212 const std::string& specConstName, 1213 const int specConstNdx) 1214 { 1215 std::ostringstream str; 1216 1217 for (int i = idxBegin; i < idxEnd; ++i) 1218 { 1219 const std::string iVal = (i == specConstNdx ? specConstName : glu::getDataTypeScalarType(type) == glu::TYPE_BOOL ? "true" : de::toString(i + 1)); 1220 str << (i != idxBegin ? ", " : "") << (castToType ? de::toString(glu::getDataTypeName(type)) + "(" + iVal + ")" : iVal); 1221 } 1222 1223 return str.str(); 1224 } 1225 1226 std::string generateArrayConstructorString (const glu::DataType elemType, 1227 const int size1, 1228 const int size2, 1229 const std::string& specConstName, 1230 const int specConstNdx) 1231 { 1232 const bool isArrayOfArray = (size2 > 0); 1233 const bool doCast = (!isDataTypeScalar(elemType)); 1234 1235 std::ostringstream arrayCtorExpr; 1236 1237 if (isArrayOfArray) 1238 { 1239 const std::string padding (36, ' '); 1240 int idxBegin = 0; 1241 int idxEnd = size2; 1242 1243 for (int iterNdx = 0; iterNdx < size1; ++iterNdx) 1244 { 1245 // Open sub-array ctor 1246 arrayCtorExpr << (iterNdx != 0 ? ",\n" + padding : "") << glu::getDataTypeName(elemType) << "[" << size2 << "]("; 1247 1248 // Sub-array constructor elements 1249 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, idxBegin, idxEnd, specConstName, specConstNdx); 1250 1251 // Close sub-array ctor, move to next range 1252 arrayCtorExpr << ")"; 1253 1254 idxBegin += size2; 1255 idxEnd += size2; 1256 } 1257 } 1258 else 1259 { 1260 // Array constructor elements 1261 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, 0, size1, specConstName, specConstNdx); 1262 } 1263 1264 return arrayCtorExpr.str(); 1265 } 1266 1267 inline GenericValue makeValue (const glu::DataType type, const int specValue) 1268 { 1269 if (type == glu::TYPE_DOUBLE) 1270 return makeValueFloat64(static_cast<double>(specValue)); 1271 else if (type == glu::TYPE_FLOAT) 1272 return makeValueFloat32(static_cast<float>(specValue)); 1273 else 1274 return makeValueInt32(specValue); 1275 } 1276 1277 deUint32 getDataTypeScalarSizeBytes (const glu::DataType dataType) 1278 { 1279 switch (getDataTypeScalarType(dataType)) 1280 { 1281 case glu::TYPE_FLOAT: 1282 case glu::TYPE_INT: 1283 case glu::TYPE_UINT: 1284 case glu::TYPE_BOOL: 1285 return 4; 1286 1287 case glu::TYPE_DOUBLE: 1288 return 8; 1289 1290 default: 1291 DE_ASSERT(false); 1292 return 0; 1293 } 1294 } 1295 1296 //! This applies to matrices/vectors/array cases. dataType must be a basic type. 1297 std::vector<OffsetValue> computeExpectedValues (const int specValue, const glu::DataType dataType, const int numCombinations) 1298 { 1299 DE_ASSERT(glu::isDataTypeScalar(dataType)); 1300 1301 std::vector<OffsetValue> expectedValues; 1302 1303 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1304 { 1305 int sum = 0; 1306 for (int i = 0; i < numCombinations; ++i) 1307 sum += (i == combNdx ? specValue : dataType == glu::TYPE_BOOL ? 1 : (i + 1)); 1308 1309 const int dataSize = getDataTypeScalarSizeBytes(dataType); 1310 expectedValues.push_back(OffsetValue(dataSize, dataSize * combNdx, makeValue(dataType, sum))); 1311 } 1312 1313 return expectedValues; 1314 } 1315 1316 inline std::string getFirstDataElementSubscriptString (const glu::DataType type) 1317 { 1318 // Grab the first element of a matrix/vector, if dealing with non-basic types. 1319 return (isDataTypeMatrix(type) ? "[0][0]" : isDataTypeVector(type) ? "[0]" : ""); 1320 } 1321 1322 //! This code will go into the main function. 1323 std::string generateShaderChecksumComputationCode (const glu::DataType elemType, 1324 const std::string& varName, 1325 const std::string& accumType, 1326 const int size1, 1327 const int size2, 1328 const int numCombinations) 1329 { 1330 std::ostringstream mainCode; 1331 1332 // Generate main code to calculate checksums for each array 1333 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1334 mainCode << " "<< accumType << " sum_" << varName << combNdx << " = " << accumType << "(0);\n"; 1335 1336 if (size2 > 0) 1337 { 1338 mainCode << "\n" 1339 << " for (int i = 0; i < " << size1 << "; ++i)\n" 1340 << " for (int j = 0; j < " << size2 << "; ++j)\n" 1341 << " {\n"; 1342 1343 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1344 mainCode << " sum_" << varName << combNdx << " += " << accumType << "(" 1345 << varName << combNdx << "[i][j]" << getFirstDataElementSubscriptString(elemType) << ");\n"; 1346 } 1347 else 1348 { 1349 mainCode << "\n" 1350 << " for (int i = 0; i < " << size1 << "; ++i)\n" 1351 << " {\n"; 1352 1353 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1354 mainCode << " sum_" << varName << combNdx << " += " << accumType << "(" 1355 << varName << combNdx << "[i]" << getFirstDataElementSubscriptString(elemType) << ");\n"; 1356 } 1357 1358 mainCode << " }\n" 1359 << "\n"; 1360 1361 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1362 mainCode << " sb_out.result[" << combNdx << "] = sum_" << varName << combNdx << ";\n"; 1363 1364 return mainCode.str(); 1365 } 1366 1367 SpecConstant makeSpecConstant (const std::string specConstName, const deUint32 specConstId, const glu::DataType type, const int specValue) 1368 { 1369 DE_ASSERT(glu::isDataTypeScalar(type)); 1370 1371 const std::string typeName(glu::getDataTypeName(type)); 1372 1373 return SpecConstant( 1374 specConstId, 1375 "layout(constant_id = ${ID}) const " + typeName + " " + specConstName + " = " + typeName + "(1);", 1376 getDataTypeScalarSizeBytes(type), makeValue(type, specValue)); 1377 } 1378 1379 } // composite_case_internal ns 1380 1381 //! Generate a CaseDefinition for a composite test using a matrix or vector (a 1-column matrix) 1382 CaseDefinition makeMatrixVectorCompositeCaseDefinition (const glu::DataType type) 1383 { 1384 using namespace composite_case_internal; 1385 1386 DE_ASSERT(!glu::isDataTypeScalar(type)); 1387 1388 const std::string varName = (glu::isDataTypeMatrix(type) ? "m" : "v"); 1389 const int numCombinations = getDataTypeScalarSize(type); 1390 const glu::DataType scalarType = glu::getDataTypeScalarType(type); 1391 const std::string typeName = glu::getDataTypeName(type); 1392 const bool isConst = (scalarType != glu::TYPE_FLOAT) && (scalarType != glu::TYPE_DOUBLE); 1393 1394 std::ostringstream globalCode; 1395 { 1396 // Build N matrices/vectors with specialization constant inserted at various locations in the constructor. 1397 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1398 globalCode << ( isConst ? "const " : "" ) << typeName << " " << varName << combNdx << " = " << typeName << "(" 1399 << generateInitializerListWithSpecConstant(type, false, 0, numCombinations, "sc0", combNdx) << ");\n"; 1400 } 1401 1402 const bool isBoolElement = (scalarType == glu::TYPE_BOOL); 1403 const int specValue = (isBoolElement ? 0 : 42); 1404 const std::string accumType = glu::getDataTypeName(isBoolElement ? glu::TYPE_INT : scalarType); 1405 1406 const int size1 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : glu::getDataTypeNumComponents(type); 1407 const int size2 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumRows(type) : 0; 1408 1409 const CaseDefinition def = 1410 { 1411 typeName, 1412 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)), 1413 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(type) * numCombinations), 1414 " " + accumType + " result[" + de::toString(numCombinations) + "];\n", 1415 globalCode.str(), 1416 generateShaderChecksumComputationCode(scalarType, varName, accumType, size1, size2, numCombinations), 1417 computeExpectedValues(specValue, scalarType, numCombinations), 1418 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0), 1419 }; 1420 return def; 1421 } 1422 1423 //! Generate a CaseDefinition for a composite test using an array, or an array of array. 1424 //! If (size1, size2) = (N, 0) -> type array[N] 1425 //! = (N, M) -> type array[N][M] 1426 CaseDefinition makeArrayCompositeCaseDefinition (const glu::DataType elemType, const int size1, const int size2 = 0) 1427 { 1428 using namespace composite_case_internal; 1429 1430 DE_ASSERT(size1 > 0); 1431 1432 const bool isArrayOfArray = (size2 > 0); 1433 const std::string varName = "a"; 1434 const std::string arraySizeDecl = "[" + de::toString(size1) + "]" + (isArrayOfArray ? "[" + de::toString(size2) + "]" : ""); 1435 const int numCombinations = (isArrayOfArray ? size1 * size2 : size1); 1436 const std::string elemTypeName (glu::getDataTypeName(elemType)); 1437 1438 std::ostringstream globalCode; 1439 { 1440 // Create several arrays with specialization constant inserted in different positions. 1441 for (int combNdx = 0; combNdx < numCombinations; ++combNdx) 1442 globalCode << elemTypeName << " " << varName << combNdx << arraySizeDecl << " = " 1443 << elemTypeName << arraySizeDecl << "(" << generateArrayConstructorString(elemType, size1, size2, "sc0", combNdx) << ");\n"; 1444 } 1445 1446 const glu::DataType scalarType = glu::getDataTypeScalarType(elemType); 1447 const bool isBoolData = (scalarType == glu::TYPE_BOOL); 1448 const int specValue = (isBoolData ? 0 : 19); 1449 const std::string caseName = (isArrayOfArray ? "array_" : "") + elemTypeName; 1450 const std::string accumType = (glu::getDataTypeName(isBoolData ? glu::TYPE_INT : scalarType)); 1451 1452 const CaseDefinition def = 1453 { 1454 caseName, 1455 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)), 1456 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(elemType) * numCombinations), 1457 " " + accumType + " result[" + de::toString(numCombinations) + "];\n", 1458 globalCode.str(), 1459 generateShaderChecksumComputationCode(elemType, varName, accumType, size1, size2, numCombinations), 1460 computeExpectedValues(specValue, scalarType, numCombinations), 1461 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0), 1462 }; 1463 return def; 1464 } 1465 1466 //! A basic struct case, where one member is a specialization constant, or a specialization constant composite 1467 //! (a matrix/vector with a spec. const. element). 1468 CaseDefinition makeStructCompositeCaseDefinition (const glu::DataType memberType) 1469 { 1470 using namespace composite_case_internal; 1471 1472 std::ostringstream globalCode; 1473 { 1474 globalCode << "struct Data {\n" 1475 << " int i;\n" 1476 << " float f;\n" 1477 << " bool b;\n" 1478 << " " << glu::getDataTypeName(memberType) << " sc;\n" 1479 << " uint ui;\n" 1480 << "};\n" 1481 << "\n" 1482 << "Data s0 = Data(3, 2.0, true, " << glu::getDataTypeName(memberType) << "(sc0), 8u);\n"; 1483 } 1484 1485 const glu::DataType scalarType = glu::getDataTypeScalarType(memberType); 1486 const bool isBoolData = (scalarType == glu::TYPE_BOOL); 1487 const int specValue = (isBoolData ? 0 : 23); 1488 const int checksum = (3 + 2 + 1 + specValue + 8); // matches the shader code 1489 const glu::DataType accumType = (isBoolData ? glu::TYPE_INT : scalarType); 1490 const std::string accumTypeStr = glu::getDataTypeName(accumType); 1491 1492 std::ostringstream mainCode; 1493 { 1494 mainCode << " " << accumTypeStr << " sum_s0 = " << accumTypeStr << "(0);\n" 1495 << "\n" 1496 << " sum_s0 += " << accumTypeStr << "(s0.i);\n" 1497 << " sum_s0 += " << accumTypeStr << "(s0.f);\n" 1498 << " sum_s0 += " << accumTypeStr << "(s0.b);\n" 1499 << " sum_s0 += " << accumTypeStr << "(s0.sc" << getFirstDataElementSubscriptString(memberType) << ");\n" 1500 << " sum_s0 += " << accumTypeStr << "(s0.ui);\n" 1501 << "\n" 1502 << " sb_out.result = sum_s0;\n"; 1503 } 1504 1505 const std::string caseName = glu::getDataTypeName(memberType); 1506 1507 const CaseDefinition def = 1508 { 1509 caseName, 1510 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)), 1511 getDataTypeScalarSizeBytes(accumType), 1512 " " + accumTypeStr + " result;\n", 1513 globalCode.str(), 1514 mainCode.str(), 1515 makeVector(OffsetValue(getDataTypeScalarSizeBytes(memberType), 0, makeValue(scalarType, checksum))), 1516 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0), 1517 }; 1518 return def; 1519 } 1520 1521 //! Specialization constants used in composites. 1522 tcu::TestCaseGroup* createCompositeTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage) 1523 { 1524 de::MovePtr<tcu::TestCaseGroup> compositeTests (new tcu::TestCaseGroup(testCtx, "composite", "specialization constants usage in composite types")); 1525 1526 // Vectors 1527 { 1528 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "vector", "")); 1529 1530 const glu::DataType types[] = 1531 { 1532 glu::TYPE_FLOAT_VEC2, 1533 glu::TYPE_FLOAT_VEC3, 1534 glu::TYPE_FLOAT_VEC4, 1535 1536 glu::TYPE_DOUBLE_VEC2, 1537 glu::TYPE_DOUBLE_VEC3, 1538 glu::TYPE_DOUBLE_VEC4, 1539 1540 glu::TYPE_BOOL_VEC2, 1541 glu::TYPE_BOOL_VEC3, 1542 glu::TYPE_BOOL_VEC4, 1543 1544 glu::TYPE_INT_VEC2, 1545 glu::TYPE_INT_VEC3, 1546 glu::TYPE_INT_VEC4, 1547 1548 glu::TYPE_UINT_VEC2, 1549 glu::TYPE_UINT_VEC3, 1550 glu::TYPE_UINT_VEC4, 1551 }; 1552 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx) 1553 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx]))); 1554 1555 compositeTests->addChild(group.release()); 1556 } 1557 1558 // Matrices 1559 { 1560 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "matrix", "")); 1561 1562 const glu::DataType types[] = 1563 { 1564 glu::TYPE_FLOAT_MAT2, 1565 glu::TYPE_FLOAT_MAT2X3, 1566 glu::TYPE_FLOAT_MAT2X4, 1567 glu::TYPE_FLOAT_MAT3X2, 1568 glu::TYPE_FLOAT_MAT3, 1569 glu::TYPE_FLOAT_MAT3X4, 1570 glu::TYPE_FLOAT_MAT4X2, 1571 glu::TYPE_FLOAT_MAT4X3, 1572 glu::TYPE_FLOAT_MAT4, 1573 1574 glu::TYPE_DOUBLE_MAT2, 1575 glu::TYPE_DOUBLE_MAT2X3, 1576 glu::TYPE_DOUBLE_MAT2X4, 1577 glu::TYPE_DOUBLE_MAT3X2, 1578 glu::TYPE_DOUBLE_MAT3, 1579 glu::TYPE_DOUBLE_MAT3X4, 1580 glu::TYPE_DOUBLE_MAT4X2, 1581 glu::TYPE_DOUBLE_MAT4X3, 1582 glu::TYPE_DOUBLE_MAT4, 1583 }; 1584 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx) 1585 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx]))); 1586 1587 compositeTests->addChild(group.release()); 1588 } 1589 1590 const glu::DataType allTypes[] = 1591 { 1592 glu::TYPE_FLOAT, 1593 glu::TYPE_FLOAT_VEC2, 1594 glu::TYPE_FLOAT_VEC3, 1595 glu::TYPE_FLOAT_VEC4, 1596 glu::TYPE_FLOAT_MAT2, 1597 glu::TYPE_FLOAT_MAT2X3, 1598 glu::TYPE_FLOAT_MAT2X4, 1599 glu::TYPE_FLOAT_MAT3X2, 1600 glu::TYPE_FLOAT_MAT3, 1601 glu::TYPE_FLOAT_MAT3X4, 1602 glu::TYPE_FLOAT_MAT4X2, 1603 glu::TYPE_FLOAT_MAT4X3, 1604 glu::TYPE_FLOAT_MAT4, 1605 1606 glu::TYPE_DOUBLE, 1607 glu::TYPE_DOUBLE_VEC2, 1608 glu::TYPE_DOUBLE_VEC3, 1609 glu::TYPE_DOUBLE_VEC4, 1610 glu::TYPE_DOUBLE_MAT2, 1611 glu::TYPE_DOUBLE_MAT2X3, 1612 glu::TYPE_DOUBLE_MAT2X4, 1613 glu::TYPE_DOUBLE_MAT3X2, 1614 glu::TYPE_DOUBLE_MAT3, 1615 glu::TYPE_DOUBLE_MAT3X4, 1616 glu::TYPE_DOUBLE_MAT4X2, 1617 glu::TYPE_DOUBLE_MAT4X3, 1618 glu::TYPE_DOUBLE_MAT4, 1619 1620 glu::TYPE_INT, 1621 glu::TYPE_INT_VEC2, 1622 glu::TYPE_INT_VEC3, 1623 glu::TYPE_INT_VEC4, 1624 1625 glu::TYPE_UINT, 1626 glu::TYPE_UINT_VEC2, 1627 glu::TYPE_UINT_VEC3, 1628 glu::TYPE_UINT_VEC4, 1629 1630 glu::TYPE_BOOL, 1631 glu::TYPE_BOOL_VEC2, 1632 glu::TYPE_BOOL_VEC3, 1633 glu::TYPE_BOOL_VEC4, 1634 }; 1635 1636 // Array cases 1637 { 1638 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "array", "")); 1639 1640 // Array of T 1641 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx) 1642 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3))); 1643 1644 // Array of array of T 1645 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx) 1646 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3, 2))); 1647 1648 // Special case - array of struct 1649 { 1650 const int checksum = (3 + 2 + 1) + (1 + 5 + 1) + (1 + 2 + 0); 1651 const CaseDefinition def = 1652 { 1653 "struct", 1654 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;", 4, makeValueInt32 (3)), 1655 SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.0;", 4, makeValueFloat32(5.0f)), 1656 SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;", 4, makeValueBool32 (false))), 1657 4, 1658 " int result;\n", 1659 1660 "struct Data {\n" 1661 " int x;\n" 1662 " float y;\n" 1663 " bool z;\n" 1664 "};\n" 1665 "\n" 1666 "Data a0[3] = Data[3](Data(sc0, 2.0, true), Data(1, sc1, true), Data(1, 2.0, sc2));\n", 1667 1668 " int sum_a0 = 0;\n" 1669 "\n" 1670 " for (int i = 0; i < 3; ++i)\n" 1671 " sum_a0 += int(a0[i].x) + int(a0[i].y) + int(a0[i].z);\n" 1672 "\n" 1673 " sb_out.result = sum_a0;\n", 1674 1675 makeVector(OffsetValue(4, 0, makeValueInt32(checksum))), 1676 (FeatureFlags)0, 1677 }; 1678 1679 group->addChild(new SpecConstantTest(testCtx, shaderStage, def)); 1680 } 1681 1682 compositeTests->addChild(group.release()); 1683 } 1684 1685 // Struct cases 1686 { 1687 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "struct", "")); 1688 1689 // Struct with one member being a specialization constant (or spec. const. composite) of a given type 1690 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx) 1691 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeStructCompositeCaseDefinition(allTypes[typeNdx]))); 1692 1693 // Special case - struct with array 1694 { 1695 const int checksum = (1 + 2 + 31 + 4 + 0); 1696 const CaseDefinition def = 1697 { 1698 "array", 1699 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 1.0;", 4, makeValueFloat32(31.0f))), 1700 4, 1701 " float result;\n", 1702 1703 "struct Data {\n" 1704 " int i;\n" 1705 " vec3 sc[3];\n" 1706 " bool b;\n" 1707 "};\n" 1708 "\n" 1709 "Data s0 = Data(1, vec3[3](vec3(2.0), vec3(sc0), vec3(4.0)), false);\n", 1710 1711 " float sum_s0 = 0;\n" 1712 "\n" 1713 " sum_s0 += float(s0.i);\n" 1714 " sum_s0 += float(s0.sc[0][0]);\n" 1715 " sum_s0 += float(s0.sc[1][0]);\n" 1716 " sum_s0 += float(s0.sc[2][0]);\n" 1717 " sum_s0 += float(s0.b);\n" 1718 "\n" 1719 " sb_out.result = sum_s0;\n", 1720 1721 makeVector(OffsetValue(4, 0, makeValueFloat32(static_cast<float>(checksum)))), 1722 (FeatureFlags)0, 1723 }; 1724 1725 group->addChild(new SpecConstantTest(testCtx, shaderStage, def)); 1726 } 1727 1728 // Special case - struct of struct 1729 { 1730 const int checksum = (1 + 2 + 11 + 4 + 1); 1731 const CaseDefinition def = 1732 { 1733 "struct", 1734 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;", 4, makeValueInt32(11))), 1735 4, 1736 " int result;\n", 1737 1738 "struct Nested {\n" 1739 " vec2 v;\n" 1740 " int sc;\n" 1741 " float f;\n" 1742 "};\n" 1743 "\n" 1744 "struct Data {\n" 1745 " uint ui;\n" 1746 " Nested s;\n" 1747 " bool b;\n" 1748 "};\n" 1749 "\n" 1750 "Data s0 = Data(1u, Nested(vec2(2.0), sc0, 4.0), true);\n", 1751 1752 " int sum_s0 = 0;\n" 1753 "\n" 1754 " sum_s0 += int(s0.ui);\n" 1755 " sum_s0 += int(s0.s.v[0]);\n" 1756 " sum_s0 += int(s0.s.sc);\n" 1757 " sum_s0 += int(s0.s.f);\n" 1758 " sum_s0 += int(s0.b);\n" 1759 "\n" 1760 " sb_out.result = sum_s0;\n", 1761 1762 makeVector(OffsetValue(4, 0, makeValueInt32(checksum))), 1763 (FeatureFlags)0, 1764 }; 1765 1766 group->addChild(new SpecConstantTest(testCtx, shaderStage, def)); 1767 } 1768 1769 compositeTests->addChild(group.release()); 1770 } 1771 1772 return compositeTests.release(); 1773 } 1774 1775 } // anonymous ns 1776 1777 tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx) 1778 { 1779 de::MovePtr<tcu::TestCaseGroup> allTests (new tcu::TestCaseGroup(testCtx, "spec_constant", "Specialization constants tests")); 1780 de::MovePtr<tcu::TestCaseGroup> graphicsGroup (new tcu::TestCaseGroup(testCtx, "graphics", "")); 1781 1782 struct StageDef 1783 { 1784 tcu::TestCaseGroup* parentGroup; 1785 const char* name; 1786 VkShaderStageFlagBits stage; 1787 }; 1788 1789 const StageDef stages[] = 1790 { 1791 { graphicsGroup.get(), "vertex", VK_SHADER_STAGE_VERTEX_BIT }, 1792 { graphicsGroup.get(), "fragment", VK_SHADER_STAGE_FRAGMENT_BIT }, 1793 { graphicsGroup.get(), "tess_control", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT }, 1794 { graphicsGroup.get(), "tess_eval", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT }, 1795 { graphicsGroup.get(), "geometry", VK_SHADER_STAGE_GEOMETRY_BIT }, 1796 { allTests.get(), "compute", VK_SHADER_STAGE_COMPUTE_BIT }, 1797 }; 1798 1799 allTests->addChild(graphicsGroup.release()); 1800 1801 for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx) 1802 { 1803 const StageDef& stage = stages[stageNdx]; 1804 de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, stage.name, "")); 1805 1806 stageGroup->addChild(createDefaultValueTests (testCtx, stage.stage)); 1807 stageGroup->addChild(createBasicSpecializationTests(testCtx, stage.stage)); 1808 stageGroup->addChild(createBuiltInOverrideTests (testCtx, stage.stage)); 1809 stageGroup->addChild(createExpressionTests (testCtx, stage.stage)); 1810 stageGroup->addChild(createCompositeTests (testCtx, stage.stage)); 1811 1812 if (stage.stage == VK_SHADER_STAGE_COMPUTE_BIT) 1813 stageGroup->addChild(createWorkGroupSizeTests(testCtx)); 1814 1815 stage.parentGroup->addChild(stageGroup.release()); 1816 } 1817 1818 return allTests.release(); 1819 } 1820 1821 } // pipeline 1822 } // vkt 1823