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 #include "vkBarrierUtil.hpp" 41 #include "vkCmdUtil.hpp" 42 #include "vkObjUtil.hpp" 43 44 #include "deUniquePtr.hpp" 45 #include "deStringUtil.hpp" 46 47 namespace vkt 48 { 49 namespace pipeline 50 { 51 52 using namespace vk; 53 54 namespace 55 { 56 57 static const char* const s_perVertexBlock = "gl_PerVertex {\n" 58 " vec4 gl_Position;\n" 59 "}"; 60 61 //! Raw memory storage for values used in test cases. 62 //! We use it to simplify test case definitions where different types are expected in the result. 63 class GenericValue 64 { 65 public: 66 GenericValue (void) { clear(); } 67 68 //! Copy up to 'size' bytes of 'data'. 69 GenericValue (const void* data, const deUint32 size) 70 { 71 DE_ASSERT(size <= sizeof(m_data)); 72 clear(); 73 deMemcpy(&m_data, data, size); 74 } 75 76 private: 77 deUint64 m_data; 78 79 void clear (void) { m_data = 0; } 80 }; 81 82 inline GenericValue makeValueBool32 (const bool a) { return GenericValue(&a, sizeof(a)); } 83 inline GenericValue makeValueInt32 (const deInt32 a) { return GenericValue(&a, sizeof(a)); } 84 // \note deInt64 not tested 85 inline GenericValue makeValueUint32 (const deUint32 a) { return GenericValue(&a, sizeof(a)); } 86 // \note deUint64 not tested 87 inline GenericValue makeValueFloat32 (const float a) { return GenericValue(&a, sizeof(a)); } 88 inline GenericValue makeValueFloat64 (const double a) { return GenericValue(&a, sizeof(a)); } 89 90 struct SpecConstant 91 { 92 deUint32 specID; //!< specialization constant ID 93 std::string declarationCode; //!< syntax to declare the constant, use ${ID} as an ID placeholder 94 deUint32 size; //!< data size on the host, 0 = no specialized value 95 GenericValue specValue; //!< specialized value passed by the API 96 97 SpecConstant (const deUint32 specID_, const std::string declarationCode_) 98 : specID (specID_) 99 , declarationCode (declarationCode_) 100 , size (0) 101 , specValue () 102 { 103 } 104 105 SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_) 106 : specID (specID_) 107 , declarationCode (declarationCode_) 108 , size (size_) 109 , specValue (specValue_) 110 { 111 } 112 }; 113 114 //! Useful when referring to a value in a buffer (i.e. check expected values in SSBO). 115 struct OffsetValue 116 { 117 deUint32 size; //!< data size in the buffer (up to sizeof(value)) 118 deUint32 offset; //!< offset into the buffer 119 GenericValue value; //!< value expected to be there 120 121 OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_) 122 : size (size_) 123 , offset (offset_) 124 , value (value_) 125 {} 126 }; 127 128 //! Get the integer value of 'size' bytes at 'memory' location. 129 deUint64 memoryAsInteger (const void* memory, const deUint32 size) 130 { 131 DE_ASSERT(size <= sizeof(deUint64)); 132 deUint64 value = 0; 133 deMemcpy(&value, memory, size); 134 return value; 135 } 136 137 inline std::string memoryAsHexString (const void* memory, const deUint32 size) 138 { 139 const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory); 140 return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size))); 141 } 142 143 void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size) 144 { 145 const bool canDisplayValue = (size <= sizeof(deUint64)); 146 log << tcu::TestLog::Message 147 << "Comparison failed for value at offset " << de::toString(offset) << ": expected " 148 << (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got " 149 << (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size) 150 << tcu::TestLog::EndMessage; 151 } 152 153 //! Check if expected values exist in the memory. 154 bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues) 155 { 156 bool ok = true; 157 log << tcu::TestLog::Section("compare", "Verify result values"); 158 159 for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it) 160 { 161 const char* const valuePtr = static_cast<const char*>(memory) + it->offset; 162 if (deMemCmp(valuePtr, &it->value, it->size) != 0) 163 { 164 ok = false; 165 logValueMismatch(log, &it->value, valuePtr, it->offset, it->size); 166 } 167 } 168 169 if (ok) 170 log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage; 171 172 log << tcu::TestLog::EndSection; 173 return ok; 174 } 175 176 //! Bundles together common test case parameters. 177 struct CaseDefinition 178 { 179 std::string name; //!< Test case name 180 std::vector<SpecConstant> specConstants; //!< list of specialization constants to declare 181 VkDeviceSize ssboSize; //!< required ssbo size in bytes 182 std::string ssboCode; //!< ssbo member definitions 183 std::string globalCode; //!< generic shader code outside the main function (e.g. declarations) 184 std::string mainCode; //!< generic shader code to execute in main (e.g. assignments) 185 std::vector<OffsetValue> expectedValues; //!< list of values to check inside the ssbo buffer 186 FeatureFlags requirements; //!< features the implementation must support to allow this test to run 187 }; 188 189 //! Manages Vulkan structures to pass specialization data. 190 class Specialization 191 { 192 public: 193 Specialization (const std::vector<SpecConstant>& specConstants); 194 195 //! Can return NULL if nothing is specialized 196 const VkSpecializationInfo* getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; } 197 198 private: 199 std::vector<GenericValue> m_data; 200 std::vector<VkSpecializationMapEntry> m_entries; 201 VkSpecializationInfo m_specialization; 202 }; 203 204 Specialization::Specialization (const std::vector<SpecConstant>& specConstants) 205 { 206 m_data.reserve(specConstants.size()); 207 m_entries.reserve(specConstants.size()); 208 209 deUint32 offset = 0; 210 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it) 211 if (it->size != 0) 212 { 213 m_data.push_back(it->specValue); 214 m_entries.push_back(makeSpecializationMapEntry(it->specID, offset, it->size)); 215 offset += (deUint32)sizeof(GenericValue); 216 } 217 218 if (m_entries.size() > 0) 219 { 220 m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size()); 221 m_specialization.pMapEntries = &m_entries[0]; 222 m_specialization.dataSize = sizeof(GenericValue) * m_data.size(); 223 m_specialization.pData = &m_data[0]; 224 } 225 else 226 deMemset(&m_specialization, 0, sizeof(m_specialization)); 227 } 228 229 class SpecConstantTest : public TestCase 230 { 231 public: 232 SpecConstantTest (tcu::TestContext& testCtx, 233 const VkShaderStageFlagBits stage, //!< which shader stage is tested 234 const CaseDefinition& caseDef); 235 236 void initPrograms (SourceCollections& programCollection) const; 237 TestInstance* createInstance (Context& context) const; 238 239 private: 240 const VkShaderStageFlagBits m_stage; 241 const CaseDefinition m_caseDef; 242 }; 243 244 SpecConstantTest::SpecConstantTest (tcu::TestContext& testCtx, 245 const VkShaderStageFlagBits stage, 246 const CaseDefinition& caseDef) 247 : TestCase (testCtx, caseDef.name, "") 248 , m_stage (stage) 249 , m_caseDef (caseDef) 250 { 251 } 252 253 //! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers. 254 std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants) 255 { 256 std::ostringstream code; 257 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it) 258 { 259 std::string decl = it->declarationCode; 260 const std::string::size_type pos = decl.find("${ID}"); 261 if (pos != std::string::npos) 262 decl.replace(pos, 5, de::toString(it->specID)); 263 code << decl << "\n"; 264 } 265 code << "\n"; 266 return code.str(); 267 } 268 269 std::string generateSSBOCode (const std::string& memberDeclarations) 270 { 271 std::ostringstream code; 272 code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n" 273 << memberDeclarations 274 << "} sb_out;\n" 275 << "\n"; 276 return code.str(); 277 } 278 279 void SpecConstantTest::initPrograms (SourceCollections& programCollection) const 280 { 281 // Always add vertex and fragment to graphics stages 282 VkShaderStageFlags requiredStages = m_stage; 283 284 if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) 285 requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; 286 287 if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) 288 requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; 289 290 // Either graphics or compute must be defined, but not both 291 DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0)); 292 293 if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT) 294 { 295 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT); 296 std::ostringstream src; 297 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 298 << "layout(location = 0) in highp vec4 position;\n" 299 << "\n" 300 << "out " << s_perVertexBlock << ";\n" 301 << "\n" 302 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 303 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 304 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 305 << "void main (void)\n" 306 << "{\n" 307 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 308 << " gl_Position = position;\n" 309 << "}\n"; 310 311 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 312 } 313 314 if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT) 315 { 316 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT); 317 std::ostringstream src; 318 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 319 << "layout(location = 0) out highp vec4 fragColor;\n" 320 << "\n" 321 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 322 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 323 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 324 << "void main (void)\n" 325 << "{\n" 326 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 327 << " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n" 328 << "}\n"; 329 330 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 331 } 332 333 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) 334 { 335 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); 336 std::ostringstream src; 337 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 338 << "layout(vertices = 3) out;\n" 339 << "\n" 340 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 341 << "\n" 342 << "out " << s_perVertexBlock << " gl_out[];\n" 343 << "\n" 344 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 345 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 346 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 347 << "void main (void)\n" 348 << "{\n" 349 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 350 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 351 << " if (gl_InvocationID == 0)\n" 352 << " {\n" 353 << " gl_TessLevelInner[0] = 3;\n" 354 << " gl_TessLevelOuter[0] = 2;\n" 355 << " gl_TessLevelOuter[1] = 2;\n" 356 << " gl_TessLevelOuter[2] = 2;\n" 357 << " }\n" 358 << "}\n"; 359 360 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 361 } 362 363 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) 364 { 365 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); 366 std::ostringstream src; 367 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 368 << "layout(triangles, equal_spacing, ccw) in;\n" 369 << "\n" 370 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 371 << "\n" 372 << "out " << s_perVertexBlock << ";\n" 373 << "\n" 374 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 375 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 376 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 377 << "void main (void)\n" 378 << "{\n" 379 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 380 << " vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n" 381 << " vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n" 382 << " vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n" 383 << " gl_Position = vec4(p0 + p1 + p2, 1.0);\n" 384 << "}\n"; 385 386 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 387 } 388 389 if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) 390 { 391 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT); 392 std::ostringstream src; 393 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 394 << "layout(triangles) in;\n" 395 << "layout(triangle_strip, max_vertices = 3) out;\n" 396 << "\n" 397 << "in " << s_perVertexBlock << " gl_in[];\n" 398 << "\n" 399 << "out " << s_perVertexBlock << ";\n" 400 << "\n" 401 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "") 402 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "") 403 << (useSpecConst ? m_caseDef.globalCode + "\n" : "") 404 << "void main (void)\n" 405 << "{\n" 406 << (useSpecConst ? m_caseDef.mainCode + "\n" : "") 407 << " gl_Position = gl_in[0].gl_Position;\n" 408 << " EmitVertex();\n" 409 << "\n" 410 << " gl_Position = gl_in[1].gl_Position;\n" 411 << " EmitVertex();\n" 412 << "\n" 413 << " gl_Position = gl_in[2].gl_Position;\n" 414 << " EmitVertex();\n" 415 << "\n" 416 << " EndPrimitive();\n" 417 << "}\n"; 418 419 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); 420 } 421 422 if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) 423 { 424 std::ostringstream src; 425 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n" 426 // Don't define work group size, use the default or specialization constants 427 << "\n" 428 << generateSpecConstantCode(m_caseDef.specConstants) 429 << generateSSBOCode(m_caseDef.ssboCode) 430 << m_caseDef.globalCode + "\n" 431 << "void main (void)\n" 432 << "{\n" 433 << m_caseDef.mainCode 434 << "}\n"; 435 436 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str()); 437 } 438 } 439 440 class ComputeTestInstance : public TestInstance 441 { 442 public: 443 ComputeTestInstance (Context& context, 444 const VkDeviceSize ssboSize, 445 const std::vector<SpecConstant>& specConstants, 446 const std::vector<OffsetValue>& expectedValues); 447 448 tcu::TestStatus iterate (void); 449 450 private: 451 const VkDeviceSize m_ssboSize; 452 const std::vector<SpecConstant> m_specConstants; 453 const std::vector<OffsetValue> m_expectedValues; 454 }; 455 456 ComputeTestInstance::ComputeTestInstance (Context& context, 457 const VkDeviceSize ssboSize, 458 const std::vector<SpecConstant>& specConstants, 459 const std::vector<OffsetValue>& expectedValues) 460 : TestInstance (context) 461 , m_ssboSize (ssboSize) 462 , m_specConstants (specConstants) 463 , m_expectedValues (expectedValues) 464 { 465 } 466 467 tcu::TestStatus ComputeTestInstance::iterate (void) 468 { 469 const DeviceInterface& vk = m_context.getDeviceInterface(); 470 const VkDevice device = m_context.getDevice(); 471 const VkQueue queue = m_context.getUniversalQueue(); 472 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 473 Allocator& allocator = m_context.getDefaultAllocator(); 474 475 // Descriptors 476 477 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 478 479 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 480 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) 481 .build(vk, device)); 482 483 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 484 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 485 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 486 487 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 488 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize); 489 490 DescriptorSetUpdateBuilder() 491 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo) 492 .update(vk, device); 493 494 // Specialization 495 496 const Specialization specialization (m_specConstants); 497 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo(); 498 499 // Pipeline 500 501 const Unique<VkShaderModule> shaderModule (createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0)); 502 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout)); 503 const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, pSpecInfo)); 504 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); 505 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 506 507 beginCommandBuffer(vk, *cmdBuffer); 508 509 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); 510 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); 511 512 vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u); 513 514 { 515 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier( 516 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize); 517 518 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 519 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL); 520 } 521 522 endCommandBuffer(vk, *cmdBuffer); 523 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 524 525 // Verify results 526 527 const Allocation& resultAlloc = resultBuffer.getAllocation(); 528 invalidateAlloc(vk, device, resultAlloc); 529 530 if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues)) 531 return tcu::TestStatus::pass("Success"); 532 else 533 return tcu::TestStatus::fail("Values did not match"); 534 } 535 536 class GraphicsTestInstance : public TestInstance 537 { 538 public: 539 GraphicsTestInstance (Context& context, 540 const VkDeviceSize ssboSize, 541 const std::vector<SpecConstant>& specConstants, 542 const std::vector<OffsetValue>& expectedValues, 543 const VkShaderStageFlagBits stage); 544 545 tcu::TestStatus iterate (void); 546 547 private: 548 const VkDeviceSize m_ssboSize; 549 const std::vector<SpecConstant> m_specConstants; 550 const std::vector<OffsetValue> m_expectedValues; 551 const VkShaderStageFlagBits m_stage; 552 }; 553 554 GraphicsTestInstance::GraphicsTestInstance (Context& context, 555 const VkDeviceSize ssboSize, 556 const std::vector<SpecConstant>& specConstants, 557 const std::vector<OffsetValue>& expectedValues, 558 const VkShaderStageFlagBits stage) 559 : TestInstance (context) 560 , m_ssboSize (ssboSize) 561 , m_specConstants (specConstants) 562 , m_expectedValues (expectedValues) 563 , m_stage (stage) 564 { 565 } 566 567 tcu::TestStatus GraphicsTestInstance::iterate (void) 568 { 569 const DeviceInterface& vk = m_context.getDeviceInterface(); 570 const VkDevice device = m_context.getDevice(); 571 const VkQueue queue = m_context.getUniversalQueue(); 572 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 573 Allocator& allocator = m_context.getDefaultAllocator(); 574 575 // Color attachment 576 577 const tcu::IVec2 renderSize = tcu::IVec2(32, 32); 578 const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM; 579 const Image colorImage (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any); 580 const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))); 581 582 // Vertex buffer 583 584 const deUint32 numVertices = 3; 585 const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices; 586 const Buffer vertexBuffer (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible); 587 588 { 589 const Allocation& alloc = vertexBuffer.getAllocation(); 590 tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr()); 591 592 pVertices[0] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f); 593 pVertices[1] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f); 594 pVertices[2] = tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f); 595 596 flushAlloc(vk, device, alloc); 597 // No barrier needed, flushed memory is automatically visible 598 } 599 600 // Descriptors 601 602 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible); 603 604 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder() 605 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS) 606 .build(vk, device)); 607 608 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder() 609 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) 610 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 611 612 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 613 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize); 614 615 DescriptorSetUpdateBuilder() 616 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo) 617 .update(vk, device); 618 619 // Specialization 620 621 const Specialization specialization (m_specConstants); 622 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo(); 623 624 // Pipeline 625 626 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, imageFormat)); 627 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y()))); 628 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout)); 629 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); 630 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool)); 631 632 GraphicsPipelineBuilder pipelineBuilder; 633 pipelineBuilder 634 .setRenderSize(renderSize) 635 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), pSpecInfo) 636 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), pSpecInfo); 637 638 if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) 639 pipelineBuilder 640 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), pSpecInfo) 641 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), pSpecInfo); 642 643 if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT) 644 pipelineBuilder 645 .setShader(vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get("geom"), pSpecInfo); 646 647 const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass)); 648 649 // Draw commands 650 651 const VkRect2D renderArea = makeRect2D(renderSize); 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 endRenderPass(vk, *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 endCommandBuffer(vk, *cmdBuffer); 686 submitCommandsAndWait(vk, device, queue, *cmdBuffer); 687 688 // Verify results 689 690 const Allocation& resultAlloc = resultBuffer.getAllocation(); 691 invalidateAlloc(vk, device, resultAlloc); 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