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