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 ¶ms)
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 ¶ms)
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 ¶ms : 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 ¶ms : 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