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