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