1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2020 The Khronos Group Inc. 6 * Copyright (c) 2020 Advanced Micro Devices, Inc. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ 21/*! 22 * \file 23 * \brief Pipeline Cache Tests 24 */ 25/*--------------------------------------------------------------------*/ 26 27#include "vktPipelineCreationCacheControlTests.hpp" 28 29#include "deRandom.hpp" 30#include "deUniquePtr.hpp" 31#include "tcuStringTemplate.hpp" 32#include "vkDeviceUtil.hpp" 33#include "vkRefUtil.hpp" 34#include "vktConstexprVectorUtil.hpp" 35#include "vktTestCase.hpp" 36#include "vktTestCaseUtil.hpp" 37 38#include <chrono> 39#include <random> 40#include <string> 41#include <vector> 42 43namespace vkt 44{ 45namespace pipeline 46{ 47namespace 48{ 49using namespace vk; 50 51using tcu::StringTemplate; 52using tcu::TestCaseGroup; 53using tcu::TestContext; 54using tcu::TestStatus; 55 56using ::std::array; 57using ::std::string; 58using ::std::vector; 59 60/*--------------------------------------------------------------------*//*! 61 * Elements common to all test types 62 *//*--------------------------------------------------------------------*/ 63namespace test_common 64{ 65using ::std::chrono::high_resolution_clock; 66using ::std::chrono::microseconds; 67 68using duration = high_resolution_clock::duration; 69using UniquePipeline = Move<VkPipeline>; 70using UniqueShaderModule = Move<VkShaderModule>; 71 72/*--------------------------------------------------------------------*//*! 73 * \brief Paired Vulkan API result with elapsed duration 74 *//*--------------------------------------------------------------------*/ 75struct TimedResult 76{ 77 VkResult result; 78 duration elapsed; 79}; 80 81/*--------------------------------------------------------------------*//*! 82 * \brief Validation function type output from vkCreate*Pipelines() 83 * 84 * \param result - VkResult returned from API call 85 * \param pipeliens - vector of pipelines created 86 * \param elapsed - high_resolution_clock::duration of time elapsed in API 87 * \param reason - output string to give the reason for failure 88 * 89 * \return QP_TEST_RESULT_PASS on success QP_TEST_RESULT_FAIL otherwise 90 *//*--------------------------------------------------------------------*/ 91using Validator = qpTestResult (*)(VkResult, const vector<UniquePipeline>&, duration, string&); 92 93static constexpr size_t VALIDATOR_ARRAY_MAX = 4; 94using ValidatorArray = ConstexprVector<Validator, VALIDATOR_ARRAY_MAX>; 95 96/*--------------------------------------------------------------------*//*! 97 * \brief Run a loop of validation tests and return the result 98 *//*--------------------------------------------------------------------*/ 99template <typename pipelines_t, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 100TestStatus validateResults(VkResult result, 101 const pipelines_t& pipelines, 102 duration elapsed, 103 const ValidatorArray& validators) 104{ 105 using de::contains; 106 static constexpr VkResult ALLOWED_RESULTS[] = {VK_SUCCESS, VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT}; 107 108 string reason; 109 110 if (contains(DE_ARRAY_BEGIN(ALLOWED_RESULTS), DE_ARRAY_END(ALLOWED_RESULTS), result) == DE_FALSE) 111 { 112 static const StringTemplate ERROR_MSG = {"Pipeline creation returned an error result: ${0}"}; 113 TCU_THROW(InternalError, ERROR_MSG.format(result).c_str()); 114 } 115 116 for (const auto& validator : validators) 117 { 118 const auto qpResult = validator(result, pipelines, elapsed, reason); 119 if (qpResult != QP_TEST_RESULT_PASS) 120 { 121 return {qpResult, reason}; 122 } 123 } 124 125 return TestStatus::pass("Test passed."); 126} 127 128/*--------------------------------------------------------------------*//*! 129 * \brief Generate an error if result does not match VK_RESULT 130 *//*--------------------------------------------------------------------*/ 131template <VkResult VK_RESULT, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 132qpTestResult checkResult(VkResult result, const vector<UniquePipeline>&, duration, string& reason) 133{ 134 if (VK_RESULT != result) 135 { 136 static const StringTemplate ERROR_MSG = {"Got ${0}, Expected ${1}"}; 137 reason = ERROR_MSG.format(result, VK_RESULT); 138 return FAIL_RESULT; 139 } 140 141 return QP_TEST_RESULT_PASS; 142} 143 144/*--------------------------------------------------------------------*//*! 145 * \brief Generate an error if pipeline[INDEX] is not valid 146 *//*--------------------------------------------------------------------*/ 147template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 148qpTestResult checkPipelineMustBeValid(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason) 149{ 150 if (pipelines.size() <= INDEX) 151 { 152 static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; 153 TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); 154 } 155 156 if (*pipelines[INDEX] == VK_NULL_HANDLE) 157 { 158 static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not a valid VkPipeline object"}; 159 reason = ERROR_MSG.format(INDEX); 160 return FAIL_RESULT; 161 } 162 163 return QP_TEST_RESULT_PASS; 164} 165 166/*--------------------------------------------------------------------*//*! 167 * \brief Generate an error if pipeline[INDEX] is not VK_NULL_HANDLE 168 *//*--------------------------------------------------------------------*/ 169template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 170qpTestResult checkPipelineMustBeNull(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason) 171{ 172 if (pipelines.size() <= INDEX) 173 { 174 static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; 175 TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); 176 } 177 178 if (*pipelines[INDEX] != VK_NULL_HANDLE) 179 { 180 static const StringTemplate ERROR_MSG = {"pipelines[${0}] is not VK_NULL_HANDLE"}; 181 reason = ERROR_MSG.format(INDEX); 182 return FAIL_RESULT; 183 } 184 185 return QP_TEST_RESULT_PASS; 186} 187 188/*--------------------------------------------------------------------*//*! 189 * \brief Generate an error if any pipeline is valid after an early-return failure 190 *//*--------------------------------------------------------------------*/ 191template <size_t INDEX, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 192qpTestResult checkPipelineNullAfterIndex(VkResult, const vector<UniquePipeline>& pipelines, duration, string& reason) 193{ 194 if (pipelines.size() <= INDEX) 195 { 196 static const StringTemplate ERROR_MSG = {"Index ${0} is not in created pipelines (pipelines.size(): ${1})"}; 197 TCU_THROW(TestError, ERROR_MSG.format(INDEX, pipelines.size())); 198 } 199 200 if (pipelines.size() - 1 == INDEX) 201 { 202 static const StringTemplate ERROR_MSG = {"Index ${0} is the last pipeline, likely a malformed test case"}; 203 TCU_THROW(TestError, ERROR_MSG.format(INDEX)); 204 } 205 206 // Only have to iterate through if the requested index is null 207 if (*pipelines[INDEX] == VK_NULL_HANDLE) 208 { 209 for (size_t i = INDEX + 1; i < pipelines.size(); ++i) 210 { 211 if (*pipelines[i] != VK_NULL_HANDLE) 212 { 213 static const StringTemplate ERROR_MSG = { 214 "pipelines[${0}] is not VK_NULL_HANDLE after a explicit early return index"}; 215 reason = ERROR_MSG.format(i); 216 return FAIL_RESULT; 217 } 218 } 219 } 220 221 return QP_TEST_RESULT_PASS; 222} 223 224/*--------------------------------------------------------------------*//*! 225 * Time limit constants 226 *//*--------------------------------------------------------------------*/ 227enum ElapsedTime 228{ 229 ELAPSED_TIME_INFINITE = microseconds{-1}.count(), 230 ELAPSED_TIME_IMMEDIATE = microseconds{500}.count(), 231 ELAPSED_TIME_FAST = microseconds{1000}.count() 232}; 233 234/*--------------------------------------------------------------------*//*! 235 * \brief Generate an error if elapsed time exceeds MAX_TIME 236 *//*--------------------------------------------------------------------*/ 237template <ElapsedTime MAX_TIME, qpTestResult FAIL_RESULT = QP_TEST_RESULT_FAIL> 238qpTestResult checkElapsedTime(VkResult, const vector<UniquePipeline>&, duration elapsed, string& reason) 239{ 240#if defined(DE_DEBUG) 241 DE_UNREF(elapsed); 242 DE_UNREF(reason); 243 244 // In debug mode timing is not likely to be accurate 245 return QP_TEST_RESULT_PASS; 246#else 247 248 using ::std::chrono::duration_cast; 249 250 static constexpr microseconds ALLOWED_TIME = microseconds{MAX_TIME}; 251 252 if (elapsed > ALLOWED_TIME) 253 { 254 static const StringTemplate ERROR_MSG = {"pipeline creation took longer than ${0}us (actual time: ${1}us)"}; 255 reason = ERROR_MSG.format(ALLOWED_TIME.count(), duration_cast<microseconds>(elapsed).count()); 256 return FAIL_RESULT; 257 } 258 259 return QP_TEST_RESULT_PASS; 260#endif 261} 262 263/*--------------------------------------------------------------------*//*! 264 * \brief Test case parameters 265 *//*--------------------------------------------------------------------*/ 266struct TestParams 267{ 268 enum CacheType 269 { 270 NO_CACHE = 0, 271 EXPLICIT_CACHE, 272 DERIVATIVE_HANDLE, 273 DERIVATIVE_INDEX 274 }; 275 276 struct Iteration 277 { 278 static constexpr size_t MAX_VARIANTS = 4; 279 using Variant = VkPipelineCreateFlags; 280 using VariantArray = ConstexprVector<Variant, MAX_VARIANTS>; 281 282 static constexpr Variant NORMAL = 0; 283 static constexpr Variant NO_COMPILE = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT; 284 static constexpr Variant EARLY_RETURN = NO_COMPILE | VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT; 285 286 static constexpr VariantArray SINGLE_NORMAL = VariantArray{NORMAL}; 287 static constexpr VariantArray SINGLE_NOCOMPILE = VariantArray{NO_COMPILE}; 288 static constexpr VariantArray BATCH_NOCOMPILE_COMPILE_NOCOMPILE = VariantArray{NO_COMPILE, NORMAL, NO_COMPILE}; 289 static constexpr VariantArray BATCH_RETURN_COMPILE_NOCOMPILE = VariantArray{EARLY_RETURN, NORMAL, NO_COMPILE}; 290 291 inline constexpr Iteration() : variants{}, validators{} {} 292 inline constexpr Iteration(const VariantArray& v, const ValidatorArray& f) : variants{v}, validators{f} {} 293 294 VariantArray variants; 295 ValidatorArray validators; 296 }; 297 298 static constexpr size_t MAX_ITERATIONS = 4; 299 using IterationArray = ConstexprVector<Iteration, MAX_ITERATIONS>; 300 301 const char* name; 302 CacheType cacheType; 303 IterationArray iterations; 304 bool useMaintenance5; 305}; 306 307/*--------------------------------------------------------------------*//*! 308 * \brief Verify extension and feature support 309 *//*--------------------------------------------------------------------*/ 310void checkSupport(Context& context, const TestParams& params) 311{ 312 static constexpr char EXT_NAME[] = "VK_EXT_pipeline_creation_cache_control"; 313 if (!context.requireDeviceFunctionality(EXT_NAME)) 314 { 315 TCU_THROW(NotSupportedError, "Extension 'VK_EXT_pipeline_creation_cache_control' is not supported"); 316 } 317 318 const auto features = context.getPipelineCreationCacheControlFeatures(); 319 if (features.pipelineCreationCacheControl == DE_FALSE) 320 { 321 TCU_THROW(NotSupportedError, "Feature 'pipelineCreationCacheControl' is not enabled"); 322 } 323 324 if (params.useMaintenance5) 325 context.requireDeviceFunctionality("VK_KHR_maintenance5"); 326} 327 328/*--------------------------------------------------------------------*//*! 329 * \brief Generate a random floating point number as a string 330 *//*--------------------------------------------------------------------*/ 331float randomFloat() 332{ 333#if !defined(DE_DEBUG) 334 static de::Random state = {::std::random_device{}()}; 335#else 336 static de::Random state = {0xDEADBEEF}; 337#endif 338 339 return state.getFloat(); 340} 341 342/*--------------------------------------------------------------------*//*! 343 * \brief Get a string of VkResults from a vector 344 *//*--------------------------------------------------------------------*/ 345string getResultsString(const vector<VkResult>& results) 346{ 347 using ::std::ostringstream; 348 349 ostringstream output; 350 351 output << "results[" << results.size() << "]={ "; 352 353 if (!results.empty()) 354 { 355 output << results[0]; 356 } 357 358 for (size_t i = 1; i < results.size(); ++i) 359 { 360 output << ", " << results[i]; 361 } 362 363 output << " }"; 364 365 return output.str(); 366} 367 368/*--------------------------------------------------------------------*//*! 369 * \brief Cast a pointer to an the expected SPIRV type 370 *//*--------------------------------------------------------------------*/ 371template <typename _t> 372inline const deUint32* shader_cast(const _t* ptr) 373{ 374 return reinterpret_cast<const deUint32*>(ptr); 375} 376 377/*--------------------------------------------------------------------*//*! 378 * \brief Capture a container of Vulkan handles into Move<> types 379 *//*--------------------------------------------------------------------*/ 380template <typename input_container_t, 381 typename handle_t = typename input_container_t::value_type, 382 typename move_t = Move<handle_t>, 383 typename deleter_t = Deleter<handle_t>, 384 typename output_t = vector<move_t>> 385output_t wrapHandles(const DeviceInterface& vk, 386 VkDevice device, 387 const input_container_t& input, 388 const VkAllocationCallbacks* allocator = DE_NULL) 389{ 390 using ::std::begin; 391 using ::std::end; 392 using ::std::transform; 393 394 auto output = output_t{}; 395 output.resize(input.size()); 396 397 struct Predicate 398 { 399 deleter_t deleter; 400 move_t operator()(handle_t v) 401 { 402 return (v != VK_NULL_HANDLE) ? move_t{check(v), deleter} : move_t{}; 403 } 404 }; 405 406 const auto wrapHandle = Predicate{deleter_t{vk, device, allocator}}; 407 408 transform(begin(input), end(input), begin(output), wrapHandle); 409 410 return output; 411} 412 413/*--------------------------------------------------------------------*//*! 414 * \brief create vkPipelineCache for test params 415 *//*--------------------------------------------------------------------*/ 416Move<VkPipelineCache> createPipelineCache(const DeviceInterface& vk, VkDevice device, const TestParams& params) 417{ 418 if (params.cacheType != TestParams::EXPLICIT_CACHE) 419 { 420 return {}; 421 } 422 423 static constexpr auto cacheInfo = VkPipelineCacheCreateInfo{ 424 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, //sType 425 DE_NULL, //pNext 426 VkPipelineCacheCreateFlags{}, //flags 427 deUintptr{0}, //initialDataSize 428 DE_NULL //pInitialData 429 }; 430 431 return createPipelineCache(vk, device, &cacheInfo); 432} 433 434/*--------------------------------------------------------------------*//*! 435 * \brief create VkPipelineLayout with descriptor sets from test parameters 436 *//*--------------------------------------------------------------------*/ 437Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vk, 438 VkDevice device, 439 const vector<VkDescriptorSetLayout>& setLayouts, 440 const TestParams&) 441{ 442 const auto layoutCreateInfo = VkPipelineLayoutCreateInfo{ 443 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType 444 DE_NULL, // pNext 445 VkPipelineLayoutCreateFlags{}, // flags 446 static_cast<deUint32>(setLayouts.size()), // setLayoutCount 447 setLayouts.data(), // pSetLayouts 448 deUint32{0u}, // pushConstantRangeCount 449 DE_NULL, // pPushConstantRanges 450 }; 451 452 return createPipelineLayout(vk, device, &layoutCreateInfo); 453} 454 455/*--------------------------------------------------------------------*//*! 456 * \brief create basic VkPipelineLayout from test parameters 457 *//*--------------------------------------------------------------------*/ 458Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vk, VkDevice device, const TestParams&) 459{ 460 static constexpr auto layoutCreateInfo = VkPipelineLayoutCreateInfo{ 461 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType 462 DE_NULL, // pNext 463 VkPipelineLayoutCreateFlags{}, // flags 464 deUint32{0u}, // setLayoutCount 465 DE_NULL, // pSetLayouts 466 deUint32{0u}, // pushConstantRangeCount 467 DE_NULL, // pPushConstantRanges 468 }; 469 470 return createPipelineLayout(vk, device, &layoutCreateInfo); 471} 472 473/*--------------------------------------------------------------------*//*! 474 * \brief Create array of shader modules 475 *//*--------------------------------------------------------------------*/ 476vector<UniqueShaderModule> createShaderModules(const DeviceInterface& vk, 477 VkDevice device, 478 const BinaryCollection& collection, 479 const vector<const char*>& names) 480{ 481 auto output = vector<UniqueShaderModule>{}; 482 output.reserve(names.size()); 483 484 for (const auto& name : names) 485 { 486 const auto& binary = collection.get(name); 487 const auto createInfo = VkShaderModuleCreateInfo{ 488 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType 489 DE_NULL, // pNext 490 VkShaderModuleCreateFlags{}, // flags 491 binary.getSize(), // codeSize 492 shader_cast(binary.getBinary()) // pCode 493 }; 494 495 output.push_back(createShaderModule(vk, device, &createInfo)); 496 } 497 498 return output; 499} 500 501/*--------------------------------------------------------------------*//*! 502 * \brief Create array of shader binding stages 503 *//*--------------------------------------------------------------------*/ 504vector<VkPipelineShaderStageCreateInfo> createShaderStages(const vector<Move<VkShaderModule>>& modules, 505 const vector<VkShaderStageFlagBits>& stages) 506{ 507 DE_ASSERT(modules.size() == stages.size()); 508 509 auto output = vector<VkPipelineShaderStageCreateInfo>{}; 510 output.reserve(modules.size()); 511 512 int i = 0; 513 514 for (const auto& module : modules) 515 { 516 const auto stageInfo = VkPipelineShaderStageCreateInfo{ 517 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType 518 DE_NULL, // pNext 519 VkPipelineShaderStageCreateFlags{}, // flags 520 stages[i++], // stage 521 *module, // module 522 "main", // pName 523 DE_NULL // pSpecializationInfo 524 }; 525 526 output.push_back(stageInfo); 527 } 528 529 return output; 530} 531 532} // namespace test_common 533 534/*--------------------------------------------------------------------*//*! 535 * \brief Graphics pipeline specific testing 536 *//*--------------------------------------------------------------------*/ 537namespace graphics_tests 538{ 539using namespace test_common; 540 541/*--------------------------------------------------------------------*//*! 542 * \brief Common graphics pipeline create info initialization 543 *//*--------------------------------------------------------------------*/ 544VkGraphicsPipelineCreateInfo getPipelineCreateInfoCommon() 545{ 546 static constexpr auto VERTEX_BINDING = VkVertexInputBindingDescription{ 547 deUint32{0u}, // binding 548 sizeof(float[4]), // stride 549 VK_VERTEX_INPUT_RATE_VERTEX // inputRate 550 }; 551 552 static constexpr auto VERTEX_ATTRIBUTE = VkVertexInputAttributeDescription{ 553 deUint32{0u}, // location 554 deUint32{0u}, // binding 555 VK_FORMAT_R32G32B32A32_SFLOAT, // format 556 deUint32{0u} // offset 557 }; 558 559 static constexpr auto VERTEX_INPUT_STATE = VkPipelineVertexInputStateCreateInfo{ 560 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType 561 DE_NULL, // pNext 562 VkPipelineVertexInputStateCreateFlags{}, // flags 563 deUint32{1u}, // vertexBindingDescriptionCount 564 &VERTEX_BINDING, // pVertexBindingDescriptions 565 deUint32{1u}, // vertexAttributeDescriptionCount 566 &VERTEX_ATTRIBUTE // pVertexAttributeDescriptions 567 }; 568 569 static constexpr auto IA_STATE = VkPipelineInputAssemblyStateCreateInfo{ 570 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType 571 DE_NULL, // pNext 572 VkPipelineInputAssemblyStateCreateFlags{}, // flags 573 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // topology 574 VK_TRUE // primitiveRestartEnable 575 }; 576 577 static constexpr auto TESSALATION_STATE = VkPipelineTessellationStateCreateInfo{ 578 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // sType 579 DE_NULL, // pNext 580 VkPipelineTessellationStateCreateFlags{}, // flags 581 deUint32{0u} // patchControlPoints 582 }; 583 584 static constexpr auto VIEWPORT = VkViewport{ 585 0.f, // x 586 0.f, // y 587 1.f, // width 588 1.f, // height 589 0.f, // minDepth 590 1.f // maxDept 591 }; 592 593 static constexpr auto SCISSOR_RECT = VkRect2D{ 594 {0, 0}, // offset 595 {256, 256} // extent 596 }; 597 598 static constexpr auto VIEWPORT_STATE = VkPipelineViewportStateCreateInfo{ 599 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType 600 DE_NULL, // pNext 601 VkPipelineViewportStateCreateFlags{}, // flags 602 deUint32{1u}, // viewportCount 603 &VIEWPORT, // pViewports 604 deUint32{1u}, // scissorCount 605 &SCISSOR_RECT // pScissors 606 }; 607 608 static constexpr auto RASTERIZATION_STATE = VkPipelineRasterizationStateCreateInfo{ 609 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType 610 DE_NULL, // pNext 611 VkPipelineRasterizationStateCreateFlags{}, // flags 612 VK_FALSE, // depthClampEnable 613 VK_TRUE, // rasterizerDiscardEnable 614 VK_POLYGON_MODE_FILL, // polygonMode 615 VK_CULL_MODE_NONE, // cullMode 616 VK_FRONT_FACE_CLOCKWISE, // frontFace 617 VK_FALSE, // depthBiasEnable 618 0.f, // depthBiasConstantFactor 619 0.f, // depthBiasClamp 620 0.f, // depthBiasSlopeFactor 621 1.f // lineWidth 622 }; 623 624 static constexpr auto SAMPLE_MASK = VkSampleMask{}; 625 626 static constexpr auto MULTISAMPLE_STATE = VkPipelineMultisampleStateCreateInfo{ 627 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType 628 DE_NULL, // pNext 629 VkPipelineMultisampleStateCreateFlags{}, // flags 630 VK_SAMPLE_COUNT_1_BIT, // rasterizationSamples 631 VK_FALSE, // sampleShadingEnable 632 0.f, // minSampleShading 633 &SAMPLE_MASK, // pSampleMask 634 VK_FALSE, // alphaToCoverageEnable 635 VK_FALSE // alphaToOneEnable 636 }; 637 638 static constexpr auto STENCIL_OP_STATE = VkStencilOpState{ 639 VK_STENCIL_OP_ZERO, // failOp 640 VK_STENCIL_OP_ZERO, // passOp 641 VK_STENCIL_OP_ZERO, // depthFailOp 642 VK_COMPARE_OP_ALWAYS, // compareOp 643 deUint32{0u}, // compareMask 644 deUint32{0u}, // writeMask 645 deUint32{0u} // reference 646 }; 647 648 static constexpr auto DEPTH_STENCIL_STATE = VkPipelineDepthStencilStateCreateInfo{ 649 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType 650 DE_NULL, // pNext 651 VkPipelineDepthStencilStateCreateFlags{}, // flags 652 VK_FALSE, // depthTestEnable 653 VK_FALSE, // depthWriteEnable 654 VK_COMPARE_OP_ALWAYS, // depthCompareOp 655 VK_FALSE, // depthBoundsTestEnable 656 VK_FALSE, // stencilTestEnable 657 STENCIL_OP_STATE, // front 658 STENCIL_OP_STATE, // back 659 0.f, // minDepthBounds 660 1.f // maxDepthBounds 661 }; 662 663 static constexpr auto COLOR_FLAGS_ALL = VkColorComponentFlags{VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | 664 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT}; 665 666 static constexpr auto COLOR_BLEND_ATTACH_STATE = VkPipelineColorBlendAttachmentState{ 667 VK_FALSE, // blendEnable 668 VK_BLEND_FACTOR_ONE, // srcColorBlendFactor 669 VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor 670 VK_BLEND_OP_ADD, // colorBlendOp 671 VK_BLEND_FACTOR_ONE, // srcAlphaBlendFactor 672 VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor 673 VK_BLEND_OP_ADD, // alphaBlendOp 674 COLOR_FLAGS_ALL // colorWriteMask 675 }; 676 677 static constexpr auto COLOR_BLEND_STATE = VkPipelineColorBlendStateCreateInfo{ 678 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType 679 DE_NULL, // pNext 680 VkPipelineColorBlendStateCreateFlags{}, // flags 681 VK_FALSE, // logicOpEnable 682 VK_LOGIC_OP_SET, // logicOp 683 deUint32{1u}, // attachmentCount 684 &COLOR_BLEND_ATTACH_STATE, // pAttachments 685 {0.f, 0.f, 0.f, 0.f} // blendConstants[4] 686 }; 687 688 static constexpr auto DYNAMIC_STATE = VkPipelineDynamicStateCreateInfo{ 689 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType; 690 DE_NULL, // pNext; 691 VkPipelineDynamicStateCreateFlags{}, // flags; 692 deUint32{0u}, // dynamicStateCount; 693 DE_NULL // pDynamicStates; 694 }; 695 696 return VkGraphicsPipelineCreateInfo{ 697 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType 698 DE_NULL, // pNext 699 VkPipelineCreateFlags{}, // flags 700 deUint32{0u}, // stageCount 701 DE_NULL, // pStages 702 &VERTEX_INPUT_STATE, // pVertexInputState 703 &IA_STATE, // pInputAssemblyState 704 &TESSALATION_STATE, // pTessellationState 705 &VIEWPORT_STATE, // pViewportState 706 &RASTERIZATION_STATE, // pRasterizationState 707 &MULTISAMPLE_STATE, // pMultisampleState 708 &DEPTH_STENCIL_STATE, // pDepthStencilState 709 &COLOR_BLEND_STATE, // pColorBlendState 710 &DYNAMIC_STATE, // pDynamicState 711 VK_NULL_HANDLE, // layout 712 VK_NULL_HANDLE, // renderPass 713 deUint32{0u}, // subpass 714 VK_NULL_HANDLE, // basePipelineHandle 715 deInt32{-1} // basePipelineIndex 716 }; 717} 718 719/*--------------------------------------------------------------------*//*! 720 * \brief create VkGraphicsPipelineCreateInfo structs from test iteration 721 *//*--------------------------------------------------------------------*/ 722vector<VkGraphicsPipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration& iteration, 723 const VkGraphicsPipelineCreateInfo& base, 724 VkPipeline basePipeline, 725 const TestParams& testParameter) 726{ 727 auto output = vector<VkGraphicsPipelineCreateInfo>{}; 728 output.reserve(iteration.variants.size()); 729 730 deInt32 count = 0; 731 deInt32 basePipelineIndex = -1; 732 733 for (VkPipelineCreateFlags flags : iteration.variants) 734 { 735 const auto curIndex = count++; 736 auto createInfo = base; 737 738 if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX) 739 { 740 if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) 741 { 742 if (basePipelineIndex != -1) 743 { 744 flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT; 745 } 746 } 747 else 748 { 749 flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; 750 751 if (basePipelineIndex == -1) 752 { 753 basePipelineIndex = curIndex; 754 } 755 } 756 } 757 758 createInfo.flags = flags; 759 createInfo.basePipelineHandle = basePipeline; 760 createInfo.basePipelineIndex = basePipelineIndex; 761 762 output.push_back(createInfo); 763 } 764 765 return output; 766} 767 768/*--------------------------------------------------------------------*//*! 769 * \brief create VkRenderPass object for Graphics test 770 *//*--------------------------------------------------------------------*/ 771Move<VkRenderPass> createRenderPass(const DeviceInterface& vk, VkDevice device, const TestParams&) 772{ 773 static constexpr auto COLOR_FORMAT = VK_FORMAT_R8G8B8A8_UNORM; 774 775 static constexpr auto COLOR_ATTACHMENT_REF = VkAttachmentReference{ 776 deUint32{0u}, // attachment 777 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // layout 778 }; 779 780 static constexpr auto SUBPASS = VkSubpassDescription{ 781 VkSubpassDescriptionFlags{}, // flags 782 VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint 783 deUint32{0u}, // inputAttachmentCount 784 DE_NULL, // pInputAttachments 785 deUint32{1u}, // colorAttachmentCount 786 &COLOR_ATTACHMENT_REF, // pColorAttachments 787 DE_NULL, // pResolveAttachments 788 DE_NULL, // pDepthStencilAttachment 789 deUint32{0u}, // preserveAttachmentCount 790 DE_NULL // pPreserveAttachments 791 }; 792 793 static constexpr auto COLOR_ATTACHMENT = VkAttachmentDescription{ 794 VkAttachmentDescriptionFlags{}, // flags 795 COLOR_FORMAT, // format 796 VK_SAMPLE_COUNT_1_BIT, // samples 797 VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp 798 VK_ATTACHMENT_STORE_OP_STORE, // storeOp 799 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp 800 VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp 801 VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout 802 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR // finalLayout 803 }; 804 805 static constexpr auto RENDER_PASS_CREATE_INFO = VkRenderPassCreateInfo{ 806 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType 807 DE_NULL, // pNext 808 VkRenderPassCreateFlags{}, // flags 809 deUint32{1u}, // attachmentCount 810 &COLOR_ATTACHMENT, // pAttachments 811 deUint32{1u}, // subpassCount 812 &SUBPASS, // pSubpasses 813 deUint32{0u}, // dependencyCount 814 DE_NULL // pDependencies 815 }; 816 817 return createRenderPass(vk, device, &RENDER_PASS_CREATE_INFO); 818} 819 820/*--------------------------------------------------------------------*//*! 821 * \brief Initialize shader programs 822 *//*--------------------------------------------------------------------*/ 823void initPrograms(SourceCollections& dst, const TestParams&) 824{ 825 using ::glu::FragmentSource; 826 using ::glu::VertexSource; 827 828 // Vertex Shader 829 static const StringTemplate VS_TEXT = {"#version 310 es\n" 830 "layout(location = 0) in vec4 position;\n" 831 "layout(location = 0) out vec3 vertColor;\n" 832 "void main (void)\n" 833 "{\n" 834 " gl_Position = position;\n" 835 " vertColor = vec3(${0}, ${1}, ${2});\n" 836 "}\n"}; 837 838 // Fragment Shader 839 static const StringTemplate FS_TEXT = {"#version 310 es\n" 840 "precision highp float;\n" 841 "layout(location = 0) in vec3 vertColor;\n" 842 "layout(location = 0) out vec4 outColor;\n" 843 "void main (void)\n" 844 "{\n" 845 " const vec3 fragColor = vec3(${0}, ${1}, ${2});\n" 846 " outColor = vec4((fragColor + vertColor) * 0.5, 1.0);\n" 847 "}\n"}; 848 849 dst.glslSources.add("vertex") << VertexSource{VS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; 850 dst.glslSources.add("fragment") << FragmentSource{FS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; 851} 852 853/*--------------------------------------------------------------------*//*! 854 * \brief return both result and elapsed time from pipeline creation 855 *//*--------------------------------------------------------------------*/ 856template <typename create_infos_t, typename pipelines_t> 857TimedResult timePipelineCreation(const DeviceInterface& vk, 858 const VkDevice device, 859 const VkPipelineCache cache, 860 const create_infos_t& createInfos, 861 pipelines_t& pipelines, 862 const VkAllocationCallbacks* pAllocator = DE_NULL) 863{ 864 DE_ASSERT(createInfos.size() <= pipelines.size()); 865 866 const auto timeStart = high_resolution_clock::now(); 867 const auto result = vk.createGraphicsPipelines( 868 device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data()); 869 const auto elapsed = high_resolution_clock::now() - timeStart; 870 return {result, elapsed}; 871} 872 873/*--------------------------------------------------------------------*//*! 874 * \brief Test instance function 875 *//*--------------------------------------------------------------------*/ 876TestStatus testInstance(Context& context, const TestParams& testParameter) 877{ 878 const auto& vk = context.getDeviceInterface(); 879 const auto device = context.getDevice(); 880 const auto pipelineCache = createPipelineCache(vk, device, testParameter); 881 const auto layout = createPipelineLayout(vk, device, testParameter); 882 const auto renderPass = createRenderPass(vk, device, testParameter); 883 // No fragment due to rasterizationDiscardEnabled 884 const auto modules = createShaderModules(vk, device, context.getBinaryCollection(), std::vector<const char*>{"vertex"}); 885 const auto shaderStages = createShaderStages(modules, std::vector<VkShaderStageFlagBits>{VK_SHADER_STAGE_VERTEX_BIT}); 886 887 // Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE 888 auto basePipeline = UniquePipeline{}; 889 890 auto baseCreateInfo = getPipelineCreateInfoCommon(); 891 baseCreateInfo.layout = layout.get(); 892 baseCreateInfo.renderPass = renderPass.get(); 893 baseCreateInfo.stageCount = static_cast<deUint32>(shaderStages.size()); 894 baseCreateInfo.pStages = shaderStages.data(); 895 896 auto results = vector<VkResult>{}; 897 results.reserve(testParameter.iterations.size()); 898 899 for (const auto& i : testParameter.iterations) 900 { 901 auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter); 902 auto created = vector<VkPipeline>{}; 903 created.resize(createInfos.size()); 904 905#ifndef CTS_USES_VULKANSC 906 std::vector<VkPipelineCreateFlags2CreateInfoKHR> flags2CreateInfo(created.size(), { VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR, 0, 0 }); 907 if (testParameter.useMaintenance5) 908 { 909 for (deUint32 ci = 0; ci < createInfos.size(); ++ci) 910 { 911 flags2CreateInfo[ci].flags = translateCreateFlag(createInfos[ci].flags); 912 flags2CreateInfo[ci].pNext = createInfos[ci].pNext; 913 createInfos[ci].flags = 0; 914 createInfos[ci].pNext = &flags2CreateInfo[ci]; 915 } 916 } 917#endif // CTS_USES_VULKANSC 918 919 const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created); 920 auto pipelines = wrapHandles(vk, device, created); 921 922 const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators); 923 if (status.getCode() != QP_TEST_RESULT_PASS) 924 { 925 return status; 926 } 927 928 if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE)) 929 { 930 for (auto& pipeline : pipelines) 931 { 932 if (*pipeline != VK_NULL_HANDLE) 933 { 934 basePipeline = pipeline; 935 break; 936 } 937 } 938 } 939 940 results.push_back(timedResult.result); 941 } 942 943 static const StringTemplate PASS_MSG = {"Test Passed. ${0}"}; 944 return TestStatus::pass(PASS_MSG.format(getResultsString(results))); 945} 946 947} // namespace graphics_tests 948 949/*--------------------------------------------------------------------*//*! 950 * \brief Compute pipeline specific testing 951 *//*--------------------------------------------------------------------*/ 952namespace compute_tests 953{ 954using namespace test_common; 955 956/*--------------------------------------------------------------------*//*! 957 * \brief create VkComputePipelineCreateInfo structs from test iteration 958 *//*--------------------------------------------------------------------*/ 959vector<VkComputePipelineCreateInfo> createPipelineCreateInfos(const TestParams::Iteration& iteration, 960 const VkComputePipelineCreateInfo& base, 961 VkPipeline basePipeline, 962 const TestParams& testParameter) 963{ 964 auto output = vector<VkComputePipelineCreateInfo>{}; 965 output.reserve(iteration.variants.size()); 966 967 deInt32 count = 0; 968 deInt32 basePipelineIndex = -1; 969 970 for (VkPipelineCreateFlags flags : iteration.variants) 971 { 972 const auto curIndex = count++; 973 auto createInfo = base; 974 975 if (testParameter.cacheType == TestParams::DERIVATIVE_INDEX) 976 { 977 if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) 978 { 979 if (basePipelineIndex != -1) 980 { 981 flags |= VK_PIPELINE_CREATE_DERIVATIVE_BIT; 982 } 983 } 984 else 985 { 986 flags |= VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT; 987 988 if (basePipelineIndex == -1) 989 { 990 basePipelineIndex = curIndex; 991 } 992 } 993 } 994 995 createInfo.flags = flags; 996 createInfo.basePipelineHandle = basePipeline; 997 createInfo.basePipelineIndex = basePipelineIndex; 998 999 output.push_back(createInfo); 1000 } 1001 1002 return output; 1003} 1004 1005/*--------------------------------------------------------------------*//*! 1006 * \brief create compute descriptor set layout 1007 *//*--------------------------------------------------------------------*/ 1008Move<VkDescriptorSetLayout> createDescriptorSetLayout(const DeviceInterface& vk, VkDevice device, const TestParams&) 1009{ 1010 static constexpr auto DESCRIPTOR_SET_LAYOUT_BINDING = VkDescriptorSetLayoutBinding{ 1011 deUint32{0u}, // binding 1012 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptorType 1013 deUint32{1u}, // descriptorCount 1014 VK_SHADER_STAGE_COMPUTE_BIT, // stageFlags 1015 DE_NULL // pImmutableSamplers 1016 }; 1017 1018 static constexpr auto DESCRIPTOR_SET_LAYOUT_CREATE_INFO = VkDescriptorSetLayoutCreateInfo{ 1019 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType 1020 DE_NULL, // pNext 1021 VkDescriptorSetLayoutCreateFlags{}, // flags 1022 deUint32{1u}, // bindingCount 1023 &DESCRIPTOR_SET_LAYOUT_BINDING // pBindings 1024 }; 1025 1026 return createDescriptorSetLayout(vk, device, &DESCRIPTOR_SET_LAYOUT_CREATE_INFO); 1027} 1028 1029/*--------------------------------------------------------------------*//*! 1030 * \brief Initialize shader programs 1031 *//*--------------------------------------------------------------------*/ 1032void initPrograms(SourceCollections& dst, const TestParams&) 1033{ 1034 using ::glu::ComputeSource; 1035 1036 static const StringTemplate CS_TEXT = {"#version 450\n" 1037 "precision highp float;\n" 1038 "layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;\n" 1039 "layout (std140, binding = 0) buffer buf { vec3 data[]; };\n" 1040 "void main (void)\n" 1041 "{\n" 1042 " data[gl_GlobalInvocationID.x] = vec3(${0}, ${1}, ${2});\n" 1043 "}\n"}; 1044 1045 dst.glslSources.add("compute") 1046 << ComputeSource{CS_TEXT.format(randomFloat(), randomFloat(), randomFloat())}; 1047} 1048 1049/*--------------------------------------------------------------------*//*! 1050 * \brief return both result and elapsed time from pipeline creation 1051 *//*--------------------------------------------------------------------*/ 1052template <typename create_infos_t, typename pipelines_t> 1053TimedResult timePipelineCreation(const DeviceInterface& vk, 1054 const VkDevice device, 1055 const VkPipelineCache cache, 1056 const create_infos_t& createInfos, 1057 pipelines_t& pipelines, 1058 const VkAllocationCallbacks* pAllocator = DE_NULL) 1059{ 1060 DE_ASSERT(createInfos.size() <= pipelines.size()); 1061 1062 const auto timeStart = high_resolution_clock::now(); 1063 const auto result = vk.createComputePipelines( 1064 device, cache, static_cast<deUint32>(createInfos.size()), createInfos.data(), pAllocator, pipelines.data()); 1065 const auto elapsed = high_resolution_clock::now() - timeStart; 1066 return {result, elapsed}; 1067} 1068 1069/*--------------------------------------------------------------------*//*! 1070 * \brief Test instance function 1071 *//*--------------------------------------------------------------------*/ 1072TestStatus testInstance(Context& context, const TestParams& testParameter) 1073{ 1074 const auto& vk = context.getDeviceInterface(); 1075 const auto device = context.getDevice(); 1076 const auto pipelineCache = createPipelineCache(vk, device, testParameter); 1077 const auto descriptorSetLayout = createDescriptorSetLayout(vk, device, testParameter); 1078 const auto pipelineLayout = createPipelineLayout(vk, device, {descriptorSetLayout.get()}, testParameter); 1079 const auto modules = createShaderModules(vk, device, context.getBinaryCollection(), {"compute"}); 1080 const auto shaderStages = createShaderStages(modules, {VK_SHADER_STAGE_COMPUTE_BIT}); 1081 1082 // Placeholder for base pipeline if using cacheType == DERIVATIVE_HANDLE 1083 auto basePipeline = UniquePipeline{}; 1084 1085 const auto baseCreateInfo = VkComputePipelineCreateInfo{ 1086 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType 1087 DE_NULL, // pNext 1088 VkPipelineCreateFlags{}, // flags 1089 shaderStages[0], // stage 1090 pipelineLayout.get(), // layout 1091 VK_NULL_HANDLE, // basePipelineHandle 1092 deInt32{-1} // basePipelineIndex 1093 }; 1094 1095 auto results = vector<VkResult>{}; 1096 results.reserve(testParameter.iterations.size()); 1097 1098 for (const auto& i : testParameter.iterations) 1099 { 1100 const auto createInfos = createPipelineCreateInfos(i, baseCreateInfo, basePipeline.get(), testParameter); 1101 auto created = vector<VkPipeline>{}; 1102 created.resize(createInfos.size()); 1103 1104 const auto timedResult = timePipelineCreation(vk, device, pipelineCache.get(), createInfos, created); 1105 auto pipelines = wrapHandles(vk, device, created); 1106 1107 const auto status = validateResults(timedResult.result, pipelines, timedResult.elapsed, i.validators); 1108 if (status.getCode() != QP_TEST_RESULT_PASS) 1109 { 1110 return status; 1111 } 1112 1113 if ((testParameter.cacheType == TestParams::DERIVATIVE_HANDLE) && (*basePipeline == VK_NULL_HANDLE)) 1114 { 1115 for (auto& pipeline : pipelines) 1116 { 1117 if (*pipeline != VK_NULL_HANDLE) 1118 { 1119 basePipeline = pipeline; 1120 break; 1121 } 1122 } 1123 } 1124 1125 results.push_back(timedResult.result); 1126 } 1127 1128 static const StringTemplate PASS_MSG = {"Test Passed. ${0}"}; 1129 return TestStatus::pass(PASS_MSG.format(getResultsString(results))); 1130} 1131 1132} // namespace compute_tests 1133 1134using namespace test_common; 1135 1136/*--------------------------------------------------------------------*//*! 1137 * \brief Duplicate single pipeline recreation with explicit caching 1138 *//*--------------------------------------------------------------------*/ 1139static constexpr TestParams DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING = 1140{ 1141 "duplicate_single_recreate_explicit_caching", 1142 TestParams::EXPLICIT_CACHE, 1143 TestParams::IterationArray 1144 { 1145 TestParams::Iteration{ 1146 // Iteration [0]: Force compilation of pipeline 1147 TestParams::Iteration::SINGLE_NORMAL, 1148 ValidatorArray{ 1149 // Fail if result is not VK_SUCCESS 1150 checkResult<VK_SUCCESS>, 1151 // Fail if pipeline is not valid 1152 checkPipelineMustBeValid<0> 1153 } 1154 }, 1155 TestParams::Iteration{ 1156 // Iteration [1]: Request compilation of same pipeline without compile 1157 TestParams::Iteration::SINGLE_NOCOMPILE, 1158 ValidatorArray{ 1159 // Warn if result is not VK_SUCCESS 1160 checkResult<VK_SUCCESS, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1161 // Warn if pipeline is not valid 1162 checkPipelineMustBeValid<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1163 // Warn if pipeline took too long 1164 checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING> 1165 } 1166 } 1167 }, 1168 false 1169}; 1170 1171/*--------------------------------------------------------------------*//*! 1172 * \brief Duplicate single pipeline recreation with no explicit cache 1173 *//*--------------------------------------------------------------------*/ 1174static constexpr TestParams DUPLICATE_SINGLE_RECREATE_NO_CACHING = 1175{ 1176 "duplicate_single_recreate_no_caching", 1177 TestParams::NO_CACHE, 1178 TestParams::IterationArray{ 1179 TestParams::Iteration{ 1180 // Iteration [0]: Force compilation of pipeline 1181 TestParams::Iteration::SINGLE_NORMAL, 1182 ValidatorArray{ 1183 // Fail if result is not VK_SUCCESS 1184 checkResult<VK_SUCCESS>, 1185 // Fail if pipeline is not valid 1186 checkPipelineMustBeValid<0> 1187 } 1188 }, 1189 TestParams::Iteration{ 1190 // Iteration [1]: Request compilation of same pipeline without compile 1191 TestParams::Iteration::SINGLE_NOCOMPILE, 1192 ValidatorArray{ 1193 // Warn if pipeline took too long 1194 checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING> 1195 } 1196 } 1197 }, 1198 false 1199}; 1200 1201/*--------------------------------------------------------------------*//*! 1202 * \brief Duplicate single pipeline recreation using derivative pipelines 1203 *//*--------------------------------------------------------------------*/ 1204static constexpr TestParams DUPLICATE_SINGLE_RECREATE_DERIVATIVE = 1205{ 1206 "duplicate_single_recreate_derivative", 1207 TestParams::DERIVATIVE_HANDLE, 1208 TestParams::IterationArray{ 1209 TestParams::Iteration{ 1210 // Iteration [0]: Force compilation of pipeline 1211 TestParams::Iteration::SINGLE_NORMAL, 1212 ValidatorArray{ 1213 // Fail if result is not VK_SUCCESS 1214 checkResult<VK_SUCCESS>, 1215 // Fail if pipeline is not valid 1216 checkPipelineMustBeValid<0> 1217 } 1218 }, 1219 TestParams::Iteration{ 1220 // Iteration [1]: Request compilation of same pipeline without compile 1221 TestParams::Iteration::SINGLE_NOCOMPILE, 1222 ValidatorArray{ 1223 // Warn if pipeline took too long 1224 checkElapsedTime<ELAPSED_TIME_FAST, QP_TEST_RESULT_QUALITY_WARNING> 1225 } 1226 } 1227 }, 1228 false 1229}; 1230 1231/*--------------------------------------------------------------------*//*! 1232 * \brief Single creation of never before seen pipeline without compile 1233 *//*--------------------------------------------------------------------*/ 1234static constexpr TestParams SINGLE_PIPELINE_NO_COMPILE = 1235{ 1236 "single_pipeline_no_compile", 1237 TestParams::NO_CACHE, 1238 TestParams::IterationArray{ 1239 TestParams::Iteration{ 1240 TestParams::Iteration::SINGLE_NOCOMPILE, 1241 ValidatorArray{ 1242 // Warn if pipeline took too long 1243 checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING> 1244 } 1245 } 1246 }, 1247 false 1248}; 1249 1250/*--------------------------------------------------------------------*//*! 1251 * \brief Batch creation of duplicate pipelines with explicit caching 1252 *//*--------------------------------------------------------------------*/ 1253static constexpr TestParams DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE = 1254{ 1255 "duplicate_batch_pipelines_explicit_cache", 1256 TestParams::EXPLICIT_CACHE, 1257 TestParams::IterationArray{ 1258 TestParams::Iteration{ 1259 TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, 1260 ValidatorArray{ 1261 // Fail if pipeline[1] is not valid 1262 checkPipelineMustBeValid<1>, 1263 // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT 1264 checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1265 // Warn if pipelines[0] is not VK_NULL_HANDLE 1266 checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1267 // Warn if pipelines[2] is not valid 1268 checkPipelineMustBeValid<2, QP_TEST_RESULT_COMPATIBILITY_WARNING> 1269 } 1270 } 1271 }, 1272 false 1273}; 1274 1275/*--------------------------------------------------------------------*//*! 1276 * \brief Batch creation of duplicate pipelines with no caching 1277 *//*--------------------------------------------------------------------*/ 1278static constexpr TestParams DUPLICATE_BATCH_PIPELINES_NO_CACHE = 1279{ 1280 "duplicate_batch_pipelines_no_cache", 1281 TestParams::NO_CACHE, 1282 TestParams::IterationArray{ 1283 TestParams::Iteration{ 1284 TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, 1285 ValidatorArray{ 1286 // Fail if pipeline[1] is not valid 1287 checkPipelineMustBeValid<1>, 1288 // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT 1289 checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1290 // Warn if pipelines[0] is not VK_NULL_HANDLE 1291 checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING> 1292 } 1293 } 1294 }, 1295 false 1296}; 1297 1298/*--------------------------------------------------------------------*//*! 1299 * \brief Batch creation of duplicate pipelines with derivative pipeline index 1300 *//*--------------------------------------------------------------------*/ 1301static constexpr TestParams DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX = 1302{ 1303 "duplicate_batch_pipelines_derivative_index", 1304 TestParams::DERIVATIVE_INDEX, 1305 TestParams::IterationArray{ 1306 TestParams::Iteration{ 1307 TestParams::Iteration::BATCH_NOCOMPILE_COMPILE_NOCOMPILE, 1308 ValidatorArray{ 1309 // Fail if pipeline[1] is not valid 1310 checkPipelineMustBeValid<1>, 1311 // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT 1312 checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1313 // Warn if pipelines[0] is not VK_NULL_HANDLE 1314 checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING> 1315 } 1316 } 1317 }, 1318 false 1319}; 1320 1321/*--------------------------------------------------------------------*//*! 1322 * \brief Batch creation of pipelines with early return 1323 *//*--------------------------------------------------------------------*/ 1324static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN = 1325{ 1326 "batch_pipelines_early_return", 1327 TestParams::NO_CACHE, 1328 TestParams::IterationArray{ 1329 TestParams::Iteration{ 1330 TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE, 1331 ValidatorArray{ 1332 // fail if a valid pipeline follows the early-return failure 1333 checkPipelineNullAfterIndex<0>, 1334 // Warn if return was not immediate 1335 checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>, 1336 // Warn if pipelines[0] is not VK_NULL_HANDLE 1337 checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1338 // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT 1339 checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING> 1340 } 1341 } 1342 }, 1343 false 1344}; 1345 1346/*--------------------------------------------------------------------*//*! 1347 * \brief Batch creation of pipelines with early return using VkPipelineCreateFlagBits2KHR from maintenance5 1348 *//*--------------------------------------------------------------------*/ 1349static constexpr TestParams BATCH_PIPELINES_EARLY_RETURN_MAINTENANCE_5 1350{ 1351 "batch_pipelines_early_return_maintenance5", 1352 TestParams::NO_CACHE, 1353 TestParams::IterationArray{ 1354 TestParams::Iteration{ 1355 TestParams::Iteration::BATCH_RETURN_COMPILE_NOCOMPILE, 1356 ValidatorArray{ 1357 // fail if a valid pipeline follows the early-return failure 1358 checkPipelineNullAfterIndex<0>, 1359 // Warn if return was not immediate 1360 checkElapsedTime<ELAPSED_TIME_IMMEDIATE, QP_TEST_RESULT_QUALITY_WARNING>, 1361 // Warn if pipelines[0] is not VK_NULL_HANDLE 1362 checkPipelineMustBeNull<0, QP_TEST_RESULT_COMPATIBILITY_WARNING>, 1363 // Warn if result is not VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT 1364 checkResult<VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT, QP_TEST_RESULT_COMPATIBILITY_WARNING> 1365 } 1366 } 1367 }, 1368 true, 1369}; 1370 1371/*--------------------------------------------------------------------*//*! 1372 * \brief Full array of test cases 1373 *//*--------------------------------------------------------------------*/ 1374static constexpr TestParams TEST_CASES[] = 1375{ 1376 SINGLE_PIPELINE_NO_COMPILE, 1377 BATCH_PIPELINES_EARLY_RETURN, 1378 DUPLICATE_SINGLE_RECREATE_EXPLICIT_CACHING, 1379 DUPLICATE_SINGLE_RECREATE_NO_CACHING, 1380 DUPLICATE_SINGLE_RECREATE_DERIVATIVE, 1381 DUPLICATE_BATCH_PIPELINES_EXPLICIT_CACHE, 1382 DUPLICATE_BATCH_PIPELINES_NO_CACHE, 1383 DUPLICATE_BATCH_PIPELINES_DERIVATIVE_INDEX, 1384 1385#ifndef CTS_USES_VULKANSC 1386 BATCH_PIPELINES_EARLY_RETURN_MAINTENANCE_5, 1387#endif // CTS_USES_VULKANSC 1388 1389}; 1390 1391/*--------------------------------------------------------------------*//*! 1392 * \brief Variadic version of de::newMovePtr 1393 *//*--------------------------------------------------------------------*/ 1394template <typename T, typename... args_t> 1395inline de::MovePtr<T> newMovePtr(args_t&&... args) 1396{ 1397 return de::MovePtr<T>(new T(::std::forward<args_t>(args)...)); 1398} 1399 1400/*--------------------------------------------------------------------*//*! 1401 * \brief Make test group consisting of graphics pipeline tests 1402 *//*--------------------------------------------------------------------*/ 1403void addGraphicsPipelineTests(TestCaseGroup& group) 1404{ 1405 using namespace graphics_tests; 1406 1407 auto tests = newMovePtr<TestCaseGroup>( 1408 group.getTestContext(), "graphics_pipelines", "Test pipeline creation cache control with graphics pipelines"); 1409 1410 for (const auto& params : TEST_CASES) 1411 { 1412 addFunctionCaseWithPrograms<const TestParams&>( 1413 tests.get(), params.name, checkSupport, initPrograms, testInstance, params); 1414 } 1415 1416 group.addChild(tests.release()); 1417} 1418 1419/*--------------------------------------------------------------------*//*! 1420 * \brief Make test group consisting of compute pipeline tests 1421 *//*--------------------------------------------------------------------*/ 1422void addComputePipelineTests(TestCaseGroup& group) 1423{ 1424 using namespace compute_tests; 1425 1426 auto tests = newMovePtr<TestCaseGroup>( 1427 group.getTestContext(), "compute_pipelines", "Test pipeline creation cache control with compute pipelines"); 1428 1429 for (const auto& params : TEST_CASES) 1430 { 1431 addFunctionCaseWithPrograms<const TestParams&>( 1432 tests.get(), params.name, checkSupport, initPrograms, testInstance, params); 1433 } 1434 1435 group.addChild(tests.release()); 1436} 1437 1438} // namespace 1439 1440/*--------------------------------------------------------------------*//*! 1441 * \brief Make pipeline creation cache control test group 1442 *//*--------------------------------------------------------------------*/ 1443TestCaseGroup* createCacheControlTests(TestContext& testCtx) 1444{ 1445 auto tests = newMovePtr<TestCaseGroup>(testCtx, "creation_cache_control"); 1446 1447 addGraphicsPipelineTests(*tests); 1448 addComputePipelineTests(*tests); 1449 1450 return tests.release(); 1451} 1452 1453} // namespace pipeline 1454 1455} // namespace vkt 1456