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