• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2024 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Pipeline Binaries Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineBinaryTests.hpp"
25 #include "vktPipelineClearUtil.hpp"
26 #include "vktPipelineImageUtil.hpp"
27 #include "vktPipelineVertexUtil.hpp"
28 #include "vktTestCase.hpp"
29 #include "vktTestCaseUtil.hpp"
30 #include "vkPipelineBinaryUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkRayTracingUtil.hpp"
38 #include "vkRef.hpp"
39 #include "vkRefUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "tcuImageCompare.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deMemory.h"
46 #include "tcuTestLog.hpp"
47 
48 #include <sstream>
49 #include <vector>
50 
51 namespace vkt::pipeline
52 {
53 
54 using namespace vk;
55 
56 enum class TestType
57 {
58     CREATE_INCOMPLETE = 0,
59     NOT_ENOUGH_SPACE,
60     DESTROY_NULL_BINARY,
61     CREATE_WITH_ZERO_BINARY_COUNT,
62     GRAPHICS_PIPELINE_FROM_INTERNAL_CACHE,
63     GRAPHICS_PIPELINE_WITH_ZERO_BINARY_COUNT,
64     COMPUTE_PIPELINE_FROM_INTERNAL_CACHE,
65     RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE,
66     RAY_TRACING_PIPELINE_FROM_PIPELINE,
67     RAY_TRACING_PIPELINE_FROM_BINARY_DATA,
68     RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT,
69     UNIQUE_KEY_PAIRS,
70 };
71 
72 enum class BinariesStatus
73 {
74     VALID = 0,
75     INVALID,
76     NOT_FOUND,
77 };
78 
79 struct TestParams
80 {
81     PipelineConstructionType pipelineConstructionType;
82     TestType type;
83     bool usePipelineLibrary;
84 };
85 
86 namespace
87 {
88 
89 class BasicComputePipelineTestInstance : public vkt::TestInstance
90 {
91 public:
92     BasicComputePipelineTestInstance(Context &context, const TestParams &testParams);
93     virtual ~BasicComputePipelineTestInstance(void) = default;
94     virtual tcu::TestStatus iterate(void) override;
95 
96 private:
97     const TestParams m_testParams;
98 };
99 
BasicComputePipelineTestInstance(Context & context,const TestParams & testParams)100 BasicComputePipelineTestInstance::BasicComputePipelineTestInstance(Context &context, const TestParams &testParams)
101     : TestInstance(context)
102     , m_testParams(testParams)
103 {
104 }
105 
iterate(void)106 tcu::TestStatus BasicComputePipelineTestInstance::iterate(void)
107 {
108     const DeviceInterface &vk = m_context.getDeviceInterface();
109     const VkDevice device     = m_context.getDevice();
110 
111     const VkDescriptorType descType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
112     const Unique<VkDescriptorPool> descriptorPool(
113         DescriptorPoolBuilder()
114             .addType(descType, 1)
115             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
116     const Unique<VkDescriptorSetLayout> descriptorSetLayout(
117         DescriptorSetLayoutBuilder().addSingleBinding(descType, VK_SHADER_STAGE_COMPUTE_BIT).build(vk, device));
118 
119     const auto pipelineLayout = makePipelineLayout(vk, device, *descriptorSetLayout);
120     const auto shaderModule   = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"));
121     VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo = initVulkanStructure();
122     pipelineFlags2CreateInfo.flags                               = VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR;
123     VkComputePipelineCreateInfo pipelineCreateInfo               = initVulkanStructure();
124     pipelineCreateInfo.pNext                                     = &pipelineFlags2CreateInfo;
125     pipelineCreateInfo.stage                                     = initVulkanStructure();
126     pipelineCreateInfo.stage.stage                               = VK_SHADER_STAGE_COMPUTE_BIT;
127     pipelineCreateInfo.stage.pName                               = "main";
128     pipelineCreateInfo.stage.module                              = *shaderModule;
129     pipelineCreateInfo.layout                                    = *pipelineLayout;
130 
131     const auto pipeline = createComputePipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo);
132 
133     if (m_testParams.type == TestType::CREATE_INCOMPLETE)
134     {
135         VkPipelineBinaryCreateInfoKHR pipelineBinaryCreateInfo = initVulkanStructure();
136         pipelineBinaryCreateInfo.pipeline                      = *pipeline;
137 
138         // check how many binaries will be created
139         VkPipelineBinaryHandlesInfoKHR binaryHandlesInfo = initVulkanStructure();
140         VK_CHECK(vk.createPipelineBinariesKHR(device, &pipelineBinaryCreateInfo, nullptr, &binaryHandlesInfo));
141 
142         std::size_t binaryCount = binaryHandlesInfo.pipelineBinaryCount;
143         if (binaryCount < 2)
144             return tcu::TestStatus::pass("Binary count too small");
145 
146         std::vector<VkPipelineBinaryKHR> binariesRaw(binaryCount, VK_NULL_HANDLE);
147         binaryHandlesInfo.pPipelineBinaries   = binariesRaw.data();
148         binaryHandlesInfo.pipelineBinaryCount = 1;
149 
150         // test that vkCreatePipelineBinariesKHR returns VK_INCOMPLETE when pipelineBinaryCount
151         // is less than the total count of binaries that might be created
152         VkResult result = vk.createPipelineBinariesKHR(device, &pipelineBinaryCreateInfo, nullptr, &binaryHandlesInfo);
153         if (result == VK_INCOMPLETE)
154             return tcu::TestStatus::pass("Pass");
155     }
156     else if (m_testParams.type == TestType::NOT_ENOUGH_SPACE)
157     {
158         PipelineBinaryWrapper binaries(vk, device);
159         binaries.createPipelineBinariesFromPipeline(*pipeline);
160 
161         VkPipelineBinaryKeyKHR binaryKey       = initVulkanStructure();
162         const VkPipelineBinaryKHR *binariesRaw = binaries.getPipelineBinaries();
163 
164         VkPipelineBinaryDataInfoKHR binaryInfo = initVulkanStructure();
165         binaryInfo.pipelineBinary              = binariesRaw[0];
166 
167         // get first binary key and data size
168         size_t binaryDataSize = 0;
169         VK_CHECK(vk.getPipelineBinaryDataKHR(device, &binaryInfo, &binaryKey, &binaryDataSize, NULL));
170         DE_ASSERT(binaryDataSize > 1);
171 
172         // try getting binary data while providing not enough space
173         std::vector<uint8_t> pipelineDataBlob(binaryDataSize);
174         --binaryDataSize;
175         VkResult result =
176             vk.getPipelineBinaryDataKHR(device, &binaryInfo, &binaryKey, &binaryDataSize, pipelineDataBlob.data());
177 
178         // check if NOT_ENOUGH_SPACE error was returned and if binaryDataSize has been updated to the correct size
179         if ((result == VK_ERROR_NOT_ENOUGH_SPACE_KHR) && (binaryDataSize == pipelineDataBlob.size()))
180             return tcu::TestStatus::pass("Pass");
181     }
182     else if (m_testParams.type == TestType::DESTROY_NULL_BINARY)
183     {
184         PipelineBinaryWrapper binaries(vk, device);
185         binaries.createPipelineBinariesFromPipeline(*pipeline);
186 
187         vk.destroyPipelineBinaryKHR(device, VK_NULL_HANDLE, nullptr);
188         return tcu::TestStatus::pass("Pass");
189     }
190     else if (m_testParams.type == TestType::CREATE_WITH_ZERO_BINARY_COUNT)
191     {
192         VkPipelineBinaryInfoKHR binaryInfo = initVulkanStructure();
193         pipelineCreateInfo.pNext           = &binaryInfo;
194         auto testPipeline                  = createComputePipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo);
195         return tcu::TestStatus::pass("Pass");
196     }
197 
198     return tcu::TestStatus::fail("Fail");
199 }
200 
201 class ComputePipelineInternalCacheTestInstance : public vkt::TestInstance
202 {
203 public:
204     ComputePipelineInternalCacheTestInstance(Context &context);
205     virtual ~ComputePipelineInternalCacheTestInstance(void) = default;
206     virtual tcu::TestStatus iterate(void) override;
207 };
208 
ComputePipelineInternalCacheTestInstance(Context & context)209 ComputePipelineInternalCacheTestInstance::ComputePipelineInternalCacheTestInstance(Context &context)
210     : TestInstance(context)
211 {
212 }
213 
iterate(void)214 tcu::TestStatus ComputePipelineInternalCacheTestInstance::iterate(void)
215 {
216     using BufferWithMemorySp = de::SharedPtr<BufferWithMemory>;
217 
218     const DeviceInterface &vk = m_context.getDeviceInterface();
219     const VkDevice device     = m_context.getDevice();
220     PipelineBinaryWrapper pipelineBinaryWrapper(vk, device);
221 
222     const VkDescriptorType descType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
223     const Unique<VkDescriptorPool> descriptorPool(
224         DescriptorPoolBuilder()
225             .addType(descType, 1)
226             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
227     const Unique<VkDescriptorSetLayout> descriptorSetLayout(
228         DescriptorSetLayoutBuilder().addSingleBinding(descType, VK_SHADER_STAGE_COMPUTE_BIT).build(vk, device));
229 
230     auto shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp")));
231     const auto pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
232 
233     // create compute pipeline
234     VkComputePipelineCreateInfo pipelineCreateInfo = initVulkanStructure();
235     pipelineCreateInfo.stage                       = initVulkanStructure();
236     pipelineCreateInfo.stage.stage                 = VK_SHADER_STAGE_COMPUTE_BIT;
237     pipelineCreateInfo.stage.pName                 = "main";
238     pipelineCreateInfo.stage.module                = *shaderModule;
239     pipelineCreateInfo.layout                      = *pipelineLayout;
240     auto pipeline(createComputePipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo));
241 
242     // create pipeline binaries from internal cache
243     BinariesStatus binariesStatus = BinariesStatus::VALID;
244     if (pipelineBinaryWrapper.createPipelineBinariesFromInternalCache(&pipelineCreateInfo))
245         binariesStatus = BinariesStatus::NOT_FOUND;
246 
247     // check pipeline binary data
248     if (binariesStatus == BinariesStatus::VALID)
249     {
250         // delete pipeline and shader module
251         pipeline     = Move<VkPipeline>();
252         shaderModule = Move<VkShaderModule>();
253 
254         std::vector<VkPipelineBinaryDataKHR> pipelineDataInfo;
255         std::vector<std::vector<uint8_t>> pipelineDataBlob;
256 
257         pipelineBinaryWrapper.getPipelineBinaryData(pipelineDataInfo, pipelineDataBlob);
258 
259         // check first blob and make sure that it does not contain only 0
260         if (std::all_of(pipelineDataBlob[0].cbegin(), pipelineDataBlob[0].cend(), [](uint8_t d) { return d == 0; }))
261             binariesStatus = BinariesStatus::INVALID;
262     }
263 
264     // test pipeline
265     Allocator &memAlloc = m_context.getDefaultAllocator();
266     const VkDeviceSize bufferSize(static_cast<VkDeviceSize>(8 * sizeof(uint32_t)));
267     VkBufferCreateInfo bufferCreateInfo(
268         makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT));
269     BufferWithMemorySp bufferWithemory(BufferWithMemorySp(
270         new BufferWithMemory(vk, device, memAlloc, bufferCreateInfo, MemoryRequirement::HostVisible)));
271 
272     const auto descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
273     VkDescriptorBufferInfo bufferDescriptorInfo(makeDescriptorBufferInfo(**bufferWithemory, 0ull, bufferSize));
274     DescriptorSetUpdateBuilder()
275         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), descType, &bufferDescriptorInfo)
276         .update(vk, device);
277 
278     // create pipeline form internal cache or fallback to normal pipeline when binary data is not valid
279     VkPipelineBinaryInfoKHR binaryInfo;
280     if (binariesStatus == BinariesStatus::VALID)
281     {
282         binaryInfo                      = pipelineBinaryWrapper.preparePipelineBinaryInfo();
283         pipelineCreateInfo.pNext        = &binaryInfo;
284         pipelineCreateInfo.stage.module = VK_NULL_HANDLE;
285     }
286     else if (binariesStatus == BinariesStatus::INVALID)
287     {
288         shaderModule                    = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"));
289         pipelineCreateInfo.stage.module = *shaderModule;
290     }
291 
292     pipeline       = createComputePipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo);
293     auto cmdPool   = makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex());
294     auto cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
295 
296     beginCommandBuffer(vk, *cmdBuffer);
297     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
298     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u,
299                              0);
300     vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
301     endCommandBuffer(vk, *cmdBuffer);
302     submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
303 
304     auto &allocation = bufferWithemory->getAllocation();
305     invalidateAlloc(vk, device, allocation);
306     uint32_t *bufferPtr = static_cast<uint32_t *>(allocation.getHostPtr());
307     for (uint32_t i = 0; i < 8; ++i)
308     {
309         if (bufferPtr[i] != i)
310             return tcu::TestStatus::fail("Invalid value in buffer");
311     }
312 
313     if (binariesStatus == BinariesStatus::VALID)
314         return tcu::TestStatus::pass("Pass");
315 
316     if (binariesStatus == BinariesStatus::INVALID)
317         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Driver wasn't able to pull out valid binary");
318 
319     //if (binariesStatus == BinariesStatus::NOT_FOUND)
320     return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline binary was not found in internal cache");
321 }
322 
323 class GraphicsPipelineInternalCacheTestInstance : public vkt::TestInstance
324 {
325 public:
326     GraphicsPipelineInternalCacheTestInstance(Context &context, const TestParams &testParams);
327     virtual ~GraphicsPipelineInternalCacheTestInstance(void) = default;
328     virtual tcu::TestStatus iterate(void) override;
329 
330 private:
331     const TestParams m_testParams;
332 };
333 
GraphicsPipelineInternalCacheTestInstance(Context & context,const TestParams & testParams)334 GraphicsPipelineInternalCacheTestInstance::GraphicsPipelineInternalCacheTestInstance(Context &context,
335                                                                                      const TestParams &testParams)
336     : TestInstance(context)
337     , m_testParams(testParams)
338 {
339 }
340 
iterate(void)341 tcu::TestStatus GraphicsPipelineInternalCacheTestInstance::iterate(void)
342 {
343     const InstanceInterface &vki           = m_context.getInstanceInterface();
344     const DeviceInterface &vk              = m_context.getDeviceInterface();
345     const VkDevice device                  = m_context.getDevice();
346     VkPhysicalDevice physicalDevice        = m_context.getPhysicalDevice();
347     vk::BinaryCollection &binaryCollection = m_context.getBinaryCollection();
348     const auto pipelineConstructionType    = m_testParams.pipelineConstructionType;
349     const uint32_t renderSize              = 8;
350     const std::vector<VkViewport> viewport{makeViewport(renderSize, renderSize)};
351     const std::vector<VkRect2D> scissor{makeRect2D(renderSize, renderSize)};
352     const Move<VkRenderPass> renderPass                   = makeRenderPass(vk, device, VK_FORMAT_R8G8B8A8_UNORM);
353     VkPipelineVertexInputStateCreateInfo vertexInputState = initVulkanStructure();
354     const VkPipelineLayoutCreateInfo pipelineLayoutInfo   = initVulkanStructure();
355     const PipelineLayoutWrapper pipelineLayout(pipelineConstructionType, vk, device, &pipelineLayoutInfo);
356     ShaderWrapper vertShader(vk, device, binaryCollection.get("vert"));
357     ShaderWrapper fragShader(vk, device, binaryCollection.get("frag"));
358     PipelineBinaryWrapper pipelineBinaryWrapper[]{
359         {vk, device},
360         {vk, device},
361         {vk, device},
362         {vk, device},
363     };
364 
365     uint32_t usedBinaryWrappersCount = 4;
366     if (pipelineConstructionType == PipelineConstructionType::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
367         usedBinaryWrappersCount = 1;
368 
369     // use local scope to delete pipeline
370     BinariesStatus binariesStatus = BinariesStatus::VALID;
371     {
372         GraphicsPipelineWrapper pipelineWrapper(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
373                                                 pipelineConstructionType);
374 
375         // pipelineBinaryInternalCache is available so create pipeline without VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR
376         pipelineWrapper.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
377             .setDefaultRasterizationState()
378             .setDefaultColorBlendState()
379             .setDefaultDepthStencilState()
380             .setDefaultMultisampleState()
381             .setMonolithicPipelineLayout(pipelineLayout)
382             .setupVertexInputState(&vertexInputState)
383             .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShader)
384             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShader)
385             .setupFragmentOutputState(*renderPass)
386             .buildPipeline();
387 
388         // reuse code to check 0 binary count
389         if (m_testParams.type == TestType::GRAPHICS_PIPELINE_WITH_ZERO_BINARY_COUNT)
390         {
391             auto pipelineCreateInfo            = pipelineWrapper.getPipelineCreateInfo();
392             VkPipelineBinaryInfoKHR binaryInfo = initVulkanStructure();
393             pipelineCreateInfo.pNext           = &binaryInfo;
394             auto testPipeline = createGraphicsPipeline(vk, device, VK_NULL_HANDLE, &pipelineCreateInfo);
395             return tcu::TestStatus::pass("Pass");
396         }
397 
398         if (pipelineConstructionType == PipelineConstructionType::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
399         {
400             const auto &pipelineCreateInfo = pipelineWrapper.getPipelineCreateInfo();
401             if (pipelineBinaryWrapper[0].createPipelineBinariesFromInternalCache(&pipelineCreateInfo))
402                 binariesStatus = BinariesStatus::NOT_FOUND;
403         }
404         else
405         {
406             for (uint32_t i = 0; i < 4; ++i)
407             {
408                 const auto &pipelinePartCreateInfo = pipelineWrapper.getPartialPipelineCreateInfo(i);
409                 if (pipelineBinaryWrapper[i].createPipelineBinariesFromInternalCache(&pipelinePartCreateInfo))
410                     binariesStatus = BinariesStatus::NOT_FOUND;
411             }
412         }
413 
414         // destroy pipeline when leaving local scope
415     }
416 
417     // check pipeline binary data
418     if (binariesStatus == BinariesStatus::VALID)
419     {
420         std::vector<VkPipelineBinaryDataKHR> pipelineDataInfo;
421         std::vector<std::vector<uint8_t>> pipelineDataBlob;
422 
423         // find pipelineBinaryWrapper that has binaries and make sure first binary is valid
424         for (uint32_t i = 0; i < usedBinaryWrappersCount; ++i)
425         {
426             if (pipelineBinaryWrapper[i].getBinariesCount() == 0)
427                 continue;
428 
429             pipelineBinaryWrapper[i].getPipelineBinaryData(pipelineDataInfo, pipelineDataBlob);
430 
431             // check first blob and make sure that it does not contain only 0
432             if (std::all_of(pipelineDataBlob[0].cbegin(), pipelineDataBlob[0].cend(), [](uint8_t d) { return d == 0; }))
433                 binariesStatus = BinariesStatus::INVALID;
434             break;
435         }
436     }
437 
438     // test pipeline
439     const VkExtent3D extent = makeExtent3D(renderSize, renderSize, 1u);
440     Allocator &memAlloc     = m_context.getDefaultAllocator();
441     const auto srr          = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
442     const auto srl          = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
443     ImageWithBuffer imageWithBuffer(vk, device, memAlloc, extent, VK_FORMAT_R8G8B8A8_UNORM,
444                                     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
445                                     VK_IMAGE_TYPE_2D, srr);
446     Move<VkImageView> imageView =
447         makeImageView(vk, device, imageWithBuffer.getImage(), VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, srr);
448     const auto framebuffer             = makeFramebuffer(vk, device, *renderPass, *imageView, renderSize, renderSize);
449     VkClearValue clearValue            = makeClearValueColor(tcu::Vec4(0.0f));
450     const VkBufferImageCopy copyRegion = makeBufferImageCopy(extent, srl);
451     const auto imageBarrier            = makeImageMemoryBarrier(
452         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
453         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageWithBuffer.getImage(), srr);
454     GraphicsPipelineWrapper pipelineWrapper(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
455                                             pipelineConstructionType);
456 
457     VkPipelineBinaryInfoKHR binaryInfo[4];
458     VkPipelineBinaryInfoKHR *binaryInfoPtr[4];
459     deMemset(binaryInfoPtr, 0, 4 * sizeof(nullptr));
460 
461     // create pipeline form internal cache or fallback to normal pipeline when binary data is not valid
462     if (binariesStatus == BinariesStatus::VALID)
463     {
464         for (uint32_t i = 0; i < usedBinaryWrappersCount; ++i)
465         {
466             binaryInfo[i]    = pipelineBinaryWrapper[i].preparePipelineBinaryInfo();
467             binaryInfoPtr[i] = &binaryInfo[i];
468         }
469     }
470 
471     pipelineWrapper.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
472         .setDefaultRasterizationState()
473         .setDefaultColorBlendState()
474         .setDefaultDepthStencilState()
475         .setDefaultMultisampleState()
476         .setMonolithicPipelineLayout(pipelineLayout)
477         .disableShaderModules(binariesStatus == BinariesStatus::VALID)
478         .setupVertexInputState(&vertexInputState, nullptr, VK_NULL_HANDLE, {}, binaryInfoPtr[0])
479         .setupPreRasterizationShaderState3(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShader, 0, {}, {},
480                                            {}, {}, {}, {}, {}, 0, 0, 0, 0, 0, {}, VK_NULL_HANDLE, {}, binaryInfoPtr[1])
481         .setupFragmentShaderState2(pipelineLayout, *renderPass, 0u, fragShader, 0, 0, 0, 0, VK_NULL_HANDLE, {}, {},
482                                    binaryInfoPtr[2])
483         .setupFragmentOutputState(*renderPass, 0, 0, 0, VK_NULL_HANDLE, {}, {}, binaryInfoPtr[3])
484         .buildPipeline(VK_NULL_HANDLE, VK_NULL_HANDLE, 0, {}, binaryInfoPtr[0]);
485 
486     const auto queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
487     const auto cmdPool =
488         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
489     const auto cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
490 
491     beginCommandBuffer(vk, *cmdBuffer);
492     beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, scissor[0], clearValue);
493     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineWrapper.getPipeline());
494     vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u);
495     endRenderPass(vk, *cmdBuffer);
496 
497     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
498                           0, 0, 0, 0, 1u, &imageBarrier);
499     vk.cmdCopyImageToBuffer(*cmdBuffer, imageWithBuffer.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
500                             imageWithBuffer.getBuffer(), 1u, &copyRegion);
501     endCommandBuffer(vk, *cmdBuffer);
502 
503     submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
504 
505     const auto &bufferAllocation = imageWithBuffer.getBufferAllocation();
506     invalidateAlloc(vk, device, bufferAllocation);
507 
508     // check just few fragments around diagonal
509     uint8_t expected[] = {255, 0, 255, 0};
510     uint8_t *bufferPtr = static_cast<uint8_t *>(bufferAllocation.getHostPtr());
511     for (uint32_t i = 0; i < 7; ++i)
512     {
513         if (deMemCmp(bufferPtr + 4 * (i * i + i), expected, 4))
514             return tcu::TestStatus::fail("Invalid fragment color");
515     }
516 
517     if (binariesStatus == BinariesStatus::VALID)
518         return tcu::TestStatus::pass("Pass");
519 
520     if (binariesStatus == BinariesStatus::INVALID)
521         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Driver wasn't able to pull out valid binary");
522 
523     //if (binariesStatus == BinariesStatus::NOT_FOUND)
524     return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline binary was not found in internal cache");
525 }
526 
527 class RayTracingPipelineTestInstance : public TestInstance
528 {
529 public:
530     RayTracingPipelineTestInstance(Context &context, const TestParams &testParams);
531     virtual ~RayTracingPipelineTestInstance(void) = default;
532 
533     virtual tcu::TestStatus iterate(void) override;
534 
535 protected:
536     VkDeviceAddress getBufferDeviceAddress(VkBuffer buffer) const;
537     de::MovePtr<BufferWithMemory> createShaderBindingTable(const VkPipeline pipeline, const uint32_t &firstGroup) const;
538     void deletePipelineAndModules(void);
539 
540 private:
541     const TestParams m_testParams;
542     Move<VkPipeline> m_pipeline;
543     std::vector<Move<VkShaderModule>> m_shaderModules;
544     std::vector<VkPipelineShaderStageCreateInfo> m_shaderCreateInfoVect;
545 };
546 
RayTracingPipelineTestInstance(Context & context,const TestParams & testParams)547 RayTracingPipelineTestInstance::RayTracingPipelineTestInstance(Context &context, const TestParams &testParams)
548     : TestInstance(context)
549     , m_testParams(testParams)
550 {
551 }
552 
iterate(void)553 tcu::TestStatus RayTracingPipelineTestInstance::iterate(void)
554 {
555     const DeviceInterface &vk = m_context.getDeviceInterface();
556     const VkDevice device     = m_context.getDevice();
557     const VkQueue queue       = m_context.getUniversalQueue();
558     Allocator &memAlloc       = m_context.getDefaultAllocator();
559     PipelineBinaryWrapper pipelineBinaryWrapper(vk, device);
560 
561     const uint32_t imageSize(8u);
562     const bool usePipelineLibrary(m_testParams.usePipelineLibrary);
563 
564     const uint32_t sgHandleSize    = m_context.getRayTracingPipelineProperties().shaderGroupHandleSize;
565     const VkFlags rayTracingStages = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR |
566                                      VK_SHADER_STAGE_MISS_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
567 
568     const VkDeviceSize resultBufferSize = imageSize * imageSize * sizeof(int);
569     const VkBufferCreateInfo resultBufferCreateInfo =
570         makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
571     de::SharedPtr<BufferWithMemory> resultBuffer = de::SharedPtr<BufferWithMemory>(
572         new BufferWithMemory(vk, device, memAlloc, resultBufferCreateInfo, MemoryRequirement::HostVisible));
573     auto &bufferAlloc = resultBuffer->getAllocation();
574     void *bufferPtr   = bufferAlloc.getHostPtr();
575     deMemset(bufferPtr, 1, static_cast<size_t>(resultBufferSize));
576     vk::flushAlloc(vk, device, bufferAlloc);
577 
578     const Move<VkDescriptorPool> descriptorPool =
579         DescriptorPoolBuilder()
580             .addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u)
581             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
582             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
583     Move<VkDescriptorSetLayout> descriptorSetLayout =
584         DescriptorSetLayoutBuilder()
585             .addSingleBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, rayTracingStages)
586             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, rayTracingStages)
587             .build(vk, device);
588     const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
589 
590     const std::pair<VkShaderStageFlagBits, std::string> stageNames[]{
591         {VK_SHADER_STAGE_RAYGEN_BIT_KHR, "rgen"},  {VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, "chit"},
592         {VK_SHADER_STAGE_MISS_BIT_KHR, "miss"},    {VK_SHADER_STAGE_INTERSECTION_BIT_KHR, "isec"},
593         {VK_SHADER_STAGE_ANY_HIT_BIT_KHR, "ahit"},
594     };
595 
596     const uint32_t shaderCount                              = DE_LENGTH_OF_ARRAY(stageNames);
597     VkPipelineShaderStageCreateInfo defaultShaderCreateInfo = initVulkanStructure();
598     defaultShaderCreateInfo.pName                           = "main";
599     m_shaderCreateInfoVect.resize(shaderCount, defaultShaderCreateInfo);
600     m_shaderModules.resize(shaderCount);
601 
602     // define shader stages
603     BinaryCollection &bc = m_context.getBinaryCollection();
604     for (uint32_t index = 0; index < shaderCount; ++index)
605     {
606         const auto &[shaderStage, shaderName] = stageNames[index];
607         m_shaderModules[index]                = createShaderModule(vk, device, bc.get(shaderName));
608         auto &shaderCreateInfo                = m_shaderCreateInfoVect[index];
609         shaderCreateInfo.stage                = shaderStage;
610         shaderCreateInfo.module               = *m_shaderModules[index];
611     }
612 
613     // define three shader groups
614     const VkRayTracingShaderGroupCreateInfoKHR defaultShaderGroupCreateInfo{
615         VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, // VkStructureType sType;
616         DE_NULL,                                                    // const void* pNext;
617         VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR,               // VkRayTracingShaderGroupTypeKHR type;
618         VK_SHADER_UNUSED_KHR,                                       // uint32_t generalShader;
619         VK_SHADER_UNUSED_KHR,                                       // uint32_t closestHitShader;
620         VK_SHADER_UNUSED_KHR,                                       // uint32_t anyHitShader;
621         VK_SHADER_UNUSED_KHR,                                       // uint32_t intersectionShader;
622         DE_NULL,                                                    // const void* pShaderGroupCaptureReplayHandle;
623     };
624     std::vector<VkRayTracingShaderGroupCreateInfoKHR> shaderGroupCreateInfoVect(3, defaultShaderGroupCreateInfo);
625     shaderGroupCreateInfoVect[0].generalShader      = 0u;
626     shaderGroupCreateInfoVect[1].type               = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR;
627     shaderGroupCreateInfoVect[1].anyHitShader       = 4u;
628     shaderGroupCreateInfoVect[1].intersectionShader = 3u;
629     shaderGroupCreateInfoVect[1].closestHitShader   = 1u;
630     shaderGroupCreateInfoVect[2].generalShader      = 2u;
631 
632     VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo = initVulkanStructure();
633     pipelineFlags2CreateInfo.flags                               = VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR;
634 
635     // define structures required for pipeline library
636     VkRayTracingPipelineInterfaceCreateInfoKHR libInterfaceInfo   = initVulkanStructure();
637     libInterfaceInfo.maxPipelineRayPayloadSize                    = static_cast<uint32_t>(sizeof(int));
638     VkRayTracingPipelineInterfaceCreateInfoKHR *pLibraryInterface = nullptr;
639 
640     // create ray tracing pipeline that will capture its data (except for RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE mode);
641     // when we use internal cache then pipeline should be created without VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR
642     void *pNext = &pipelineFlags2CreateInfo;
643     if (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE)
644     {
645         pNext                          = nullptr;
646         pipelineFlags2CreateInfo.flags = 0;
647     }
648 
649     // create ray tracing pipeline library instead of regular ray tracing pipeline
650     if (usePipelineLibrary)
651     {
652         pNext = &pipelineFlags2CreateInfo;
653         pipelineFlags2CreateInfo.flags |= VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR;
654         pLibraryInterface = &libInterfaceInfo;
655     }
656 
657     Move<VkPipeline> pipelineLibrary;
658     VkPipelineLibraryCreateInfoKHR libraryInfo = initVulkanStructure();
659     Move<VkPipelineLayout> pipelineLayout      = makePipelineLayout(vk, device, *descriptorSetLayout);
660     VkRayTracingPipelineCreateInfoKHR pipelineCreateInfo{
661         VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR,
662         pNext,
663         0,                                // VkPipelineCreateFlags                       flags;
664         shaderCount,                      // uint32_t                                    stageCount;
665         m_shaderCreateInfoVect.data(),    // const VkPipelineShaderStageCreateInfo*      pStages;
666         3u,                               // uint32_t                                    groupCount;
667         shaderGroupCreateInfoVect.data(), // const VkRayTracingShaderGroupCreateInfoKHR* pGroups;
668         1u,                               // uint32_t                                    maxPipelineRayRecursionDepth;
669         DE_NULL,                          // VkPipelineLibraryCreateInfoKHR*             pLibraryInfo;
670         pLibraryInterface,                // VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface;
671         DE_NULL,                          // const VkPipelineDynamicStateCreateInfo*     pDynamicState;
672         *pipelineLayout,                  // VkPipelineLayout                            layout;
673         VK_NULL_HANDLE,                   // VkPipeline                                  basePipelineHandle;
674         0,                                // int32_t                                     basePipelineIndex;
675     };
676     m_pipeline = createRayTracingPipelineKHR(vk, device, VK_NULL_HANDLE, VK_NULL_HANDLE, &pipelineCreateInfo);
677     BinariesStatus binariesStatus = BinariesStatus::VALID;
678 
679     if (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE)
680     {
681         // reuse this test to also check if pipeline key is valid
682         auto pipelineKey = pipelineBinaryWrapper.getPipelineKey(&pipelineCreateInfo);
683         if (pipelineKey.keySize == 0)
684             return tcu::TestStatus::fail("vkGetPipelineKeyKHR returned keySize == 0");
685 
686         // create pipeline binary objects from pipeline
687         pipelineBinaryWrapper.createPipelineBinariesFromPipeline(*m_pipeline);
688 
689         // delete pipeline and shader modules after creating binaries
690         deletePipelineAndModules();
691     }
692     else if (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA)
693     {
694         // create pipeline binary objects from pipeline
695         pipelineBinaryWrapper.createPipelineBinariesFromPipeline(*m_pipeline);
696 
697         // read binaries data out of the device
698         std::vector<VkPipelineBinaryDataKHR> pipelineDataInfo;
699         std::vector<std::vector<uint8_t>> pipelineDataBlob;
700         pipelineBinaryWrapper.getPipelineBinaryData(pipelineDataInfo, pipelineDataBlob);
701 
702         // clear pipeline binaries objects
703         pipelineBinaryWrapper.deletePipelineBinariesKeepKeys();
704 
705         // recreate binaries from data blobs
706         pipelineBinaryWrapper.createPipelineBinariesFromBinaryData(pipelineDataInfo);
707 
708         // delete pipeline and shader modules after creating binaries
709         deletePipelineAndModules();
710     }
711     else if (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE)
712     {
713         if (pipelineBinaryWrapper.createPipelineBinariesFromInternalCache(&pipelineCreateInfo))
714             binariesStatus = BinariesStatus::NOT_FOUND;
715         else
716         {
717             // delete pipeline and shader modules after creating binaries
718             deletePipelineAndModules();
719 
720             std::vector<VkPipelineBinaryDataKHR> pipelineDataInfo;
721             std::vector<std::vector<uint8_t>> pipelineDataBlob;
722 
723             // attempt to call vkGetPipelineBinaryDataKHR
724             pipelineBinaryWrapper.getPipelineBinaryData(pipelineDataInfo, pipelineDataBlob);
725 
726             // check first blob and make sure that it does not contain only 0
727             if (std::all_of(pipelineDataBlob[0].cbegin(), pipelineDataBlob[0].cend(), [](uint8_t d) { return d == 0; }))
728                 binariesStatus = BinariesStatus::INVALID;
729         }
730     }
731     else if (m_testParams.type == TestType::RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT)
732     {
733         VkPipelineBinaryInfoKHR binaryInfo = initVulkanStructure();
734         pipelineCreateInfo.pNext           = &binaryInfo;
735         auto testPipeline =
736             createRayTracingPipelineKHR(vk, device, VK_NULL_HANDLE, VK_NULL_HANDLE, &pipelineCreateInfo);
737         return tcu::TestStatus::pass("Pass");
738     }
739 
740     // recreate pipeline using binaries or fallback to normal pipelines when binaries aren't found
741     VkPipelineBinaryInfoKHR binaryInfo;
742     if (binariesStatus == BinariesStatus::VALID)
743     {
744         binaryInfo               = pipelineBinaryWrapper.preparePipelineBinaryInfo();
745         pipelineCreateInfo.pNext = &binaryInfo;
746 
747         if (usePipelineLibrary)
748         {
749             pipelineFlags2CreateInfo.flags = VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR;
750             binaryInfo.pNext               = &pipelineFlags2CreateInfo;
751         }
752     }
753     else
754     {
755         for (uint32_t index = 0; index < shaderCount; ++index)
756         {
757             const auto &[shaderStage, shaderName] = stageNames[index];
758             m_shaderModules[index]                = createShaderModule(vk, device, bc.get(shaderName));
759             auto &shaderCreateInfo                = m_shaderCreateInfoVect[index];
760             shaderCreateInfo.stage                = shaderStage;
761             shaderCreateInfo.module               = *m_shaderModules[index];
762         }
763         pipelineCreateInfo.pStages = m_shaderCreateInfoVect.data();
764     }
765 
766     if (usePipelineLibrary)
767     {
768         // create raytracing pipeline library from pipeline library
769         pipelineLibrary = createRayTracingPipelineKHR(vk, device, VK_NULL_HANDLE, VK_NULL_HANDLE, &pipelineCreateInfo);
770 
771         // create raytracing pipeline from pipeline library
772         libraryInfo.libraryCount = 1u;
773         libraryInfo.pLibraries   = &*pipelineLibrary;
774 
775         pipelineCreateInfo                              = initVulkanStructure();
776         pipelineCreateInfo.maxPipelineRayRecursionDepth = 1u;
777         pipelineCreateInfo.pLibraryInterface            = pLibraryInterface;
778         pipelineCreateInfo.layout                       = *pipelineLayout;
779         pipelineCreateInfo.pLibraryInfo                 = &libraryInfo;
780     }
781 
782     m_pipeline = createRayTracingPipelineKHR(vk, device, VK_NULL_HANDLE, VK_NULL_HANDLE, &pipelineCreateInfo);
783 
784     auto rgenShaderBT = createShaderBindingTable(*m_pipeline, 0);
785     auto chitShaderBT = createShaderBindingTable(*m_pipeline, 1);
786     auto missShaderBT = createShaderBindingTable(*m_pipeline, 2);
787 
788     auto &makeSDARegion     = makeStridedDeviceAddressRegionKHR;
789     const auto rgenSBTR     = makeSDARegion(getBufferDeviceAddress(**rgenShaderBT), sgHandleSize, sgHandleSize);
790     const auto chitSBTR     = makeSDARegion(getBufferDeviceAddress(**chitShaderBT), sgHandleSize, sgHandleSize);
791     const auto missSBTR     = makeSDARegion(getBufferDeviceAddress(**missShaderBT), sgHandleSize, sgHandleSize);
792     const auto callableSBTR = makeSDARegion(DE_NULL, 0, 0);
793 
794     auto tlas      = makeTopLevelAccelerationStructure();
795     auto cmdPool   = createCommandPool(vk, device, 0, m_context.getUniversalQueueFamilyIndex());
796     auto cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
797 
798     beginCommandBuffer(vk, *cmdBuffer, 0u);
799 
800     // build acceleration structure - single, big aabb
801     auto blas = makeBottomLevelAccelerationStructure();
802     blas->setGeometryData(
803         {
804             {0.0, 0.0, -8.0},
805             {8.0, 8.0, -1.0},
806         },
807         false, 0);
808     blas->createAndBuild(vk, device, *cmdBuffer, memAlloc);
809     tlas->setInstanceCount(1);
810     tlas->addInstance(de::SharedPtr<BottomLevelAccelerationStructure>(blas.release()));
811     tlas->createAndBuild(vk, device, *cmdBuffer, memAlloc);
812 
813     // update descriptor sets
814     {
815         typedef DescriptorSetUpdateBuilder::Location DSL;
816         VkWriteDescriptorSetAccelerationStructureKHR as = initVulkanStructure();
817         as.accelerationStructureCount                   = 1;
818         as.pAccelerationStructures                      = tlas->getPtr();
819         const VkDescriptorBufferInfo ssbo               = makeDescriptorBufferInfo(**resultBuffer, 0u, VK_WHOLE_SIZE);
820         DescriptorSetUpdateBuilder()
821             .writeSingle(*descriptorSet, DSL::binding(0u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &as)
822             .writeSingle(*descriptorSet, DSL::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssbo)
823             .update(vk, device);
824     }
825 
826     // wait for data transfers
827     const VkMemoryBarrier bufferUploadBarrier =
828         makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
829     cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
830                              VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &bufferUploadBarrier, 1u);
831 
832     // wait for as build
833     const VkMemoryBarrier asBuildBarrier = makeMemoryBarrier(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
834                                                              VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR);
835     cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
836                              VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, &asBuildBarrier, 1u);
837 
838     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *m_pipeline);
839 
840     // generate result
841     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, *pipelineLayout, 0, 1, &*descriptorSet,
842                              0, DE_NULL);
843     cmdTraceRays(vk, *cmdBuffer, &rgenSBTR, &missSBTR, &chitSBTR, &callableSBTR, imageSize, imageSize, 1);
844 
845     const VkMemoryBarrier postTraceMemoryBarrier =
846         makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
847     cmdPipelineMemoryBarrier(vk, *cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
848                              VK_PIPELINE_STAGE_TRANSFER_BIT, &postTraceMemoryBarrier);
849 
850     endCommandBuffer(vk, *cmdBuffer);
851 
852     submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
853 
854     // verify result buffer
855     const uint32_t fragmentCount = imageSize * imageSize;
856     uint32_t brightRedCount      = 0;
857     uint32_t darkRedCount        = 0;
858     auto resultAllocation        = resultBuffer->getAllocation();
859     auto data                    = static_cast<uint32_t *>(resultAllocation.getHostPtr());
860     invalidateMappedMemoryRange(vk, device, resultAllocation.getMemory(), resultAllocation.getOffset(),
861                                 resultBufferSize);
862     for (uint32_t i = 0; i < fragmentCount; ++i)
863     {
864         uint32_t value = data[i];
865         brightRedCount += (value == 0xFF0000FF);
866         darkRedCount += (value == 0xFF000080);
867     }
868 
869     // expect half of fragments to have dark red color and other half bright red color
870     // check also if colors in top corrners are ok
871     if (((brightRedCount + darkRedCount) == fragmentCount) && (data[0] == 0xFF0000FF) &&
872         (data[imageSize - 1] == 0xFF000080))
873     {
874         if (binariesStatus == BinariesStatus::VALID)
875             return tcu::TestStatus::pass("Pass");
876 
877         if (binariesStatus == BinariesStatus::INVALID)
878             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Driver wasn't able to pull out valid binary");
879 
880         //if (binariesStatus == BinariesStatus::NOT_FOUND)
881         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Pipeline binary was not found in internal cache");
882     }
883 
884     tcu::TextureFormat imageFormat(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
885     tcu::PixelBufferAccess resultAccess(imageFormat, imageSize, imageSize, 1, data);
886     m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Result", "")
887                                         << tcu::TestLog::Image("Output", "", resultAccess) << tcu::TestLog::EndImageSet;
888 
889     return tcu::TestStatus::fail("Fail");
890 }
891 
getBufferDeviceAddress(VkBuffer buffer) const892 VkDeviceAddress RayTracingPipelineTestInstance::getBufferDeviceAddress(VkBuffer buffer) const
893 {
894     const DeviceInterface &vk                   = m_context.getDeviceInterface();
895     const VkDevice device                       = m_context.getDevice();
896     VkBufferDeviceAddressInfo deviceAddressInfo = initVulkanStructure();
897 
898     deviceAddressInfo.buffer = buffer;
899     return vk.getBufferDeviceAddress(device, &deviceAddressInfo);
900 };
901 
createShaderBindingTable(const VkPipeline pipeline,const uint32_t & firstGroup) const902 de::MovePtr<BufferWithMemory> RayTracingPipelineTestInstance::createShaderBindingTable(const VkPipeline pipeline,
903                                                                                        const uint32_t &firstGroup) const
904 {
905     const DeviceInterface &vk = m_context.getDeviceInterface();
906     const VkDevice device     = m_context.getDevice();
907     Allocator &memAlloc       = m_context.getDefaultAllocator();
908     const uint32_t sgHandleSize(m_context.getRayTracingPipelineProperties().shaderGroupHandleSize);
909     std::vector<uint8_t> shaderHandles(sgHandleSize);
910 
911     vk.getRayTracingShaderGroupHandlesKHR(device, pipeline, firstGroup, 1u, static_cast<uint32_t>(shaderHandles.size()),
912                                           de::dataOrNull(shaderHandles));
913 
914     const auto totalEntrySize         = deAlign32(sgHandleSize, sgHandleSize);
915     const VkBufferUsageFlags sbtFlags = VK_BUFFER_USAGE_TRANSFER_DST_BIT |
916                                         VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR |
917                                         VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
918     VkBufferCreateInfo sbtCreateInfo = makeBufferCreateInfo(totalEntrySize, sbtFlags);
919 
920     const MemoryRequirement sbtMemRequirements =
921         MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress | MemoryRequirement::Any;
922     de::MovePtr<BufferWithMemory> sbtBuffer =
923         de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, memAlloc, sbtCreateInfo, sbtMemRequirements));
924     vk::Allocation &sbtAlloc = sbtBuffer->getAllocation();
925 
926     deMemcpy(sbtAlloc.getHostPtr(), shaderHandles.data(), sgHandleSize);
927     flushMappedMemoryRange(vk, device, sbtAlloc.getMemory(), sbtAlloc.getOffset(), VK_WHOLE_SIZE);
928 
929     return sbtBuffer;
930 }
931 
deletePipelineAndModules()932 void RayTracingPipelineTestInstance::deletePipelineAndModules()
933 {
934     m_pipeline = Move<VkPipeline>();
935     for (uint32_t index = 0; index < (uint32_t)m_shaderModules.size(); ++index)
936     {
937         m_shaderModules[index]               = Move<VkShaderModule>();
938         m_shaderCreateInfoVect[index].module = VK_NULL_HANDLE;
939     }
940 }
941 
942 class UniqueKayPairsTestInstance : public vkt::TestInstance
943 {
944 public:
945     UniqueKayPairsTestInstance(Context &context, const TestParams &testParams);
946     virtual ~UniqueKayPairsTestInstance(void) = default;
947     virtual tcu::TestStatus iterate(void) override;
948 
949 private:
950     const TestParams m_testParams;
951 };
952 
UniqueKayPairsTestInstance(Context & context,const TestParams & testParams)953 UniqueKayPairsTestInstance::UniqueKayPairsTestInstance(Context &context, const TestParams &testParams)
954     : TestInstance(context)
955     , m_testParams(testParams)
956 {
957 }
958 
iterate(void)959 tcu::TestStatus UniqueKayPairsTestInstance::iterate(void)
960 {
961     const InstanceInterface &vki           = m_context.getInstanceInterface();
962     const DeviceInterface &vkd             = m_context.getDeviceInterface();
963     const VkDevice vkDevice                = m_context.getDevice();
964     VkPhysicalDevice vkPhysicalDevice      = m_context.getPhysicalDevice();
965     vk::BinaryCollection &binaryCollection = m_context.getBinaryCollection();
966     const auto pipelineConstructionType    = m_testParams.pipelineConstructionType;
967     const std::vector<VkViewport> viewport{makeViewport(16, 16)};
968     const std::vector<VkRect2D> scissor{makeRect2D(16, 16)};
969     const Move<VkRenderPass> renderPass                 = makeRenderPass(vkd, vkDevice, VK_FORMAT_R8G8B8A8_UNORM);
970     const VkPipelineLayoutCreateInfo pipelineLayoutInfo = initVulkanStructure();
971     const PipelineLayoutWrapper pipelineLayout(pipelineConstructionType, vkd, vkDevice, &pipelineLayoutInfo);
972 
973     ShaderWrapper vertShaderModule = ShaderWrapper(vkd, vkDevice, binaryCollection.get("vert"), 0);
974     ShaderWrapper fragShaderModule = ShaderWrapper(vkd, vkDevice, binaryCollection.get("frag"), 0);
975     GraphicsPipelineWrapper gpwCombinations[]{
976         {vki, vkd, vkPhysicalDevice, vkDevice, m_context.getDeviceExtensions(), pipelineConstructionType},
977         {vki, vkd, vkPhysicalDevice, vkDevice, m_context.getDeviceExtensions(), pipelineConstructionType},
978         {vki, vkd, vkPhysicalDevice, vkDevice, m_context.getDeviceExtensions(), pipelineConstructionType},
979         {vki, vkd, vkPhysicalDevice, vkDevice, m_context.getDeviceExtensions(), pipelineConstructionType},
980     };
981     PipelineBinaryWrapper binaries[]{
982         {vkd, vkDevice},
983         {vkd, vkDevice},
984         {vkd, vkDevice},
985         {vkd, vkDevice},
986     };
987     std::vector<VkPipelineBinaryDataKHR> pipelineDataInfo[4];
988     std::vector<std::vector<uint8_t>> pipelineDataBlob[4];
989 
990     const float specializationData[][2]{
991         {0.2f, 0.3f},
992         {0.2f, 0.4f},
993         {0.1f, 0.3f},
994         {0.1f, 0.4f},
995     };
996 
997     // specialization constants
998     const auto entrySize = static_cast<uintptr_t>(sizeof(float));
999     const VkSpecializationMapEntry specializationMap[]{
1000         //    constantID        offset                                size
1001         {0u, 0u, entrySize},
1002         {1u, static_cast<uint32_t>(entrySize), entrySize},
1003     };
1004     VkSpecializationInfo specializationInfo{
1005         2u,                                                    // uint32_t mapEntryCount;
1006         specializationMap,                                     // const VkSpecializationMapEntry* pMapEntries;
1007         static_cast<uintptr_t>(sizeof(specializationData[0])), // uintptr_t dataSize;
1008         DE_NULL,                                               // const void* pData;
1009     };
1010 
1011     for (int32_t i = 0; i < 4; ++i)
1012     {
1013         specializationInfo.pData = specializationData[i];
1014         gpwCombinations[i]
1015             .setPipelineCreateFlags2(VK_PIPELINE_CREATE_2_CAPTURE_DATA_BIT_KHR)
1016             .setDefaultRasterizationState()
1017             .setDefaultColorBlendState()
1018             .setDefaultDepthStencilState()
1019             .setDefaultMultisampleState()
1020             .setMonolithicPipelineLayout(pipelineLayout)
1021             .setupVertexInputState()
1022             .setupPreRasterizationShaderState(viewport, scissor, pipelineLayout, *renderPass, 0u, vertShaderModule, 0,
1023                                               ShaderWrapper(), ShaderWrapper(), ShaderWrapper(), &specializationInfo)
1024             .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragShaderModule, 0, 0, &specializationInfo)
1025             .setupFragmentOutputState(*renderPass)
1026             .buildPipeline();
1027 
1028         binaries[i].createPipelineBinariesFromPipeline(gpwCombinations[i].getPipeline());
1029 
1030         // read binaries data out of the device
1031         binaries[i].getPipelineBinaryData(pipelineDataInfo[i], pipelineDataBlob[i]);
1032 
1033         for (uint32_t currDataBlobIndex = 0; currDataBlobIndex < (uint32_t)pipelineDataBlob[i].size();
1034              ++currDataBlobIndex)
1035         {
1036             const auto &currDataBlob = pipelineDataBlob[i][currDataBlobIndex];
1037 
1038             // compare with binaries from previous pipelines
1039             for (int32_t p = i - 1; p >= 0; --p)
1040             {
1041                 for (uint32_t prevDataBlobIndex = 0; prevDataBlobIndex < (uint32_t)pipelineDataBlob[p].size();
1042                      ++prevDataBlobIndex)
1043                 {
1044                     const auto &prevDataBlob = pipelineDataBlob[p][prevDataBlobIndex];
1045 
1046                     // skip if blob has different size
1047                     if (currDataBlob.size() != prevDataBlob.size())
1048                         continue;
1049 
1050                     // if pipeline binary data is the same but the keys are different flag a QualityWarning
1051                     if (deMemCmp(currDataBlob.data(), prevDataBlob.data(), currDataBlob.size()) == 0)
1052                     {
1053                         const auto &currKey = binaries[i].getBinaryKeys()[currDataBlobIndex];
1054                         const auto &prevKey = binaries[p].getBinaryKeys()[prevDataBlobIndex];
1055 
1056                         if (currKey.keySize != prevKey.keySize)
1057                             continue;
1058 
1059                         if (deMemCmp(currKey.key, prevKey.key, currKey.keySize) != 0)
1060                             TCU_THROW(QualityWarning, "Multiple keys generated for identical binaries");
1061                     }
1062                 }
1063             }
1064         }
1065     }
1066 
1067     // there is no duplicated pipeline binary data
1068     return tcu::TestStatus::pass("Pass");
1069 }
1070 
1071 class BaseTestCase : public vkt::TestCase
1072 {
1073 public:
BaseTestCase(tcu::TestContext & testContext,const std::string & name,TestParams && testParams)1074     BaseTestCase(tcu::TestContext &testContext, const std::string &name, TestParams &&testParams)
1075         : vkt::TestCase(testContext, name)
1076         , m_testParams(std::move(testParams))
1077     {
1078     }
1079     virtual ~BaseTestCase(void) = default;
1080 
1081     virtual void initPrograms(SourceCollections &programCollection) const override;
1082     virtual void checkSupport(Context &context) const override;
1083     virtual TestInstance *createInstance(Context &context) const override;
1084 
1085 protected:
1086     TestParams m_testParams;
1087 };
1088 
initPrograms(SourceCollections & programCollection) const1089 void BaseTestCase::initPrograms(SourceCollections &programCollection) const
1090 {
1091     if ((m_testParams.type == TestType::GRAPHICS_PIPELINE_FROM_INTERNAL_CACHE) ||
1092         (m_testParams.type == TestType::GRAPHICS_PIPELINE_WITH_ZERO_BINARY_COUNT))
1093     {
1094         programCollection.glslSources.add("vert")
1095             << glu::VertexSource("#version 450\n"
1096                                  "out gl_PerVertex { vec4 gl_Position; };\n"
1097                                  "void main (void)\n"
1098                                  "{\n"
1099                                  "  const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
1100                                  "  const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
1101                                  "  gl_Position = vec4(x, y, 0.0, 1.0);\n"
1102                                  "}\n");
1103 
1104         programCollection.glslSources.add("frag")
1105             << glu::FragmentSource("#version 450\n"
1106                                    "layout(location = 0) out highp vec4 fragColor;\n"
1107                                    "void main (void)\n"
1108                                    "{\n"
1109                                    "  fragColor = vec4(1.0, 0.0, 1.0, 0.0);\n"
1110                                    "}\n");
1111     }
1112     else if ((m_testParams.type == TestType::CREATE_INCOMPLETE) || (m_testParams.type == TestType::NOT_ENOUGH_SPACE) ||
1113              (m_testParams.type == TestType::DESTROY_NULL_BINARY) ||
1114              (m_testParams.type == TestType::CREATE_WITH_ZERO_BINARY_COUNT) ||
1115              (m_testParams.type == TestType::COMPUTE_PIPELINE_FROM_INTERNAL_CACHE))
1116     {
1117         programCollection.glslSources.add("comp")
1118             << glu::ComputeSource("#version 310 es\n"
1119                                   "layout(local_size_x = 8) in;\n"
1120                                   "layout(binding = 0) writeonly buffer Output\n"
1121                                   "{\n"
1122                                   "  uint v[];\n"
1123                                   "} output_data;\n"
1124                                   "void main()\n"
1125                                   "{\n"
1126                                   "  output_data.v[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;\n"
1127                                   "}");
1128     }
1129     else if ((m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE) ||
1130              (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE) ||
1131              (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA) ||
1132              (m_testParams.type == TestType::RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT))
1133     {
1134         const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
1135 
1136         programCollection.glslSources.add("rgen")
1137             << glu::RaygenSource(
1138                    "#version 460 core\n"
1139                    "#extension GL_EXT_ray_tracing : require\n"
1140                    "layout(location = 0) rayPayloadEXT int payload;\n"
1141 
1142                    "layout(set = 0, binding = 0) uniform accelerationStructureEXT tlas;\n"
1143                    "layout(set = 0, binding = 1, std430) writeonly buffer Result {\n"
1144                    "    int value[];\n"
1145                    "} result;\n"
1146 
1147                    "void main()\n"
1148                    "{\n"
1149                    "  float tmin        =  0.0;\n"
1150                    "  float tmax        = 10.0;\n"
1151                    "  vec3  origin      = vec3(float(gl_LaunchIDEXT.x) + 0.5f, float(gl_LaunchIDEXT.y) + 0.5f, 2.0);\n"
1152                    "  vec3  direction   = vec3(0.0,0.0,-1.0);\n"
1153                    "  uint  resultIndex = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x;\n"
1154 
1155                    "  traceRayEXT(tlas, gl_RayFlagsCullBackFacingTrianglesEXT, 0xFF, 0, 0, 0, origin, tmin, direction, "
1156                    "tmax, 0);\n"
1157                    // to be able to display result in cherry this is interpreated as r8g8b8a8 during verification
1158                    // we are using only red but we need to add alpha (note: r and a may be swapped depending on endianness)
1159                    "  result.value[resultIndex] = payload + 0xFF000000;\n"
1160                    "};\n")
1161             << buildOptions;
1162 
1163         programCollection.glslSources.add("isec") << glu::IntersectionSource("#version 460 core\n"
1164                                                                              "#extension GL_EXT_ray_tracing : require\n"
1165 
1166                                                                              "void main()\n"
1167                                                                              "{\n"
1168                                                                              "  if (gl_WorldRayOriginEXT.x < 4.0)\n"
1169                                                                              "    reportIntersectionEXT(2.0, 0);\n"
1170                                                                              "}\n")
1171                                                   << buildOptions;
1172 
1173         programCollection.glslSources.add("ahit")
1174             << glu::AnyHitSource("#version 460 core\n"
1175                                  "#extension GL_EXT_ray_tracing : require\n"
1176                                  "layout(location = 0) rayPayloadInEXT int payload;\n"
1177                                  "void main()\n"
1178                                  "{\n"
1179                                  "  payload = 128;\n"
1180                                  "}\n")
1181             << buildOptions;
1182 
1183         programCollection.glslSources.add("chit")
1184             << glu::ClosestHitSource("#version 460 core\n"
1185                                      "#extension GL_EXT_ray_tracing : require\n"
1186                                      "layout(location = 0) rayPayloadInEXT int payload;\n"
1187                                      "\n"
1188                                      "void main()\n"
1189                                      "{\n"
1190                                      "  payload = payload + 127;\n"
1191                                      "}\n")
1192             << buildOptions;
1193 
1194         programCollection.glslSources.add("miss")
1195             << glu::MissSource("#version 460 core\n"
1196                                "#extension GL_EXT_ray_tracing : require\n"
1197                                "layout(location = 0) rayPayloadInEXT int payload;\n"
1198                                "void main()\n"
1199                                "{\n"
1200                                "  payload = 128;\n"
1201                                "}\n")
1202             << buildOptions;
1203     }
1204     else if (m_testParams.type == TestType::UNIQUE_KEY_PAIRS)
1205     {
1206         programCollection.glslSources.add("vert")
1207             << glu::VertexSource("#version 450\n"
1208                                  "layout(location = 0) in vec4 position;\n"
1209                                  "layout(location = 0) out highp vec4 vertColor;\n"
1210                                  "layout(constant_id = 0) const float vColor = 0.1;\n"
1211                                  "out gl_PerVertex { vec4 gl_Position; };\n"
1212                                  "void main (void)\n"
1213                                  "{\n"
1214                                  "  vertColor = vec4(vColor * gl_VertexIndex);\n"
1215                                  "  gl_Position = position;\n"
1216                                  "}\n");
1217         programCollection.glslSources.add("frag")
1218             << glu::FragmentSource("#version 450\n"
1219                                    "layout(location = 0) in highp vec4 vertColor;\n"
1220                                    "layout(location = 0) out highp vec4 fragColor;\n"
1221                                    "layout(constant_id = 1) const float fColor = 0.1;\n"
1222                                    "void main (void)\n"
1223                                    "{\n"
1224                                    "  fragColor = vertColor + vec4(fColor);\n"
1225                                    "}\n");
1226     }
1227 }
1228 
checkSupport(Context & context) const1229 void BaseTestCase::checkSupport(Context &context) const
1230 {
1231     const auto &vki           = context.getInstanceInterface();
1232     const auto physicalDevice = context.getPhysicalDevice();
1233 
1234     context.requireDeviceFunctionality("VK_KHR_pipeline_binary");
1235     checkPipelineConstructionRequirements(vki, physicalDevice, m_testParams.pipelineConstructionType);
1236 
1237     if ((m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE) ||
1238         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE) ||
1239         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA) ||
1240         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT))
1241     {
1242         context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
1243         context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
1244         context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
1245     }
1246 
1247     if (m_testParams.usePipelineLibrary)
1248         context.requireDeviceFunctionality("VK_KHR_pipeline_library");
1249 
1250     const auto &binaryProperties = context.getPipelineBinaryProperties();
1251     if ((m_testParams.type == TestType::GRAPHICS_PIPELINE_FROM_INTERNAL_CACHE) ||
1252         (m_testParams.type == TestType::COMPUTE_PIPELINE_FROM_INTERNAL_CACHE) ||
1253         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE))
1254     {
1255         if (!binaryProperties.pipelineBinaryInternalCache)
1256             TCU_THROW(NotSupportedError, "pipelineBinaryInternalCache property not supported");
1257     }
1258 }
1259 
createInstance(Context & context) const1260 TestInstance *BaseTestCase::createInstance(Context &context) const
1261 {
1262     if ((m_testParams.type == TestType::CREATE_INCOMPLETE) || (m_testParams.type == TestType::NOT_ENOUGH_SPACE) ||
1263         (m_testParams.type == TestType::DESTROY_NULL_BINARY) ||
1264         (m_testParams.type == TestType::CREATE_WITH_ZERO_BINARY_COUNT))
1265         return new BasicComputePipelineTestInstance(context, m_testParams);
1266     if ((m_testParams.type == TestType::GRAPHICS_PIPELINE_FROM_INTERNAL_CACHE) ||
1267         (m_testParams.type == TestType::GRAPHICS_PIPELINE_WITH_ZERO_BINARY_COUNT))
1268         return new GraphicsPipelineInternalCacheTestInstance(context, m_testParams);
1269     if (m_testParams.type == TestType::COMPUTE_PIPELINE_FROM_INTERNAL_CACHE)
1270         return new ComputePipelineInternalCacheTestInstance(context);
1271     if ((m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE) ||
1272         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE) ||
1273         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA) ||
1274         (m_testParams.type == TestType::RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT))
1275         return new RayTracingPipelineTestInstance(context, m_testParams);
1276 
1277     return new UniqueKayPairsTestInstance(context, m_testParams);
1278 }
1279 
1280 } // namespace
1281 
addPipelineBinaryDedicatedTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType,de::MovePtr<tcu::TestCaseGroup> binaryGroup)1282 de::MovePtr<tcu::TestCaseGroup> addPipelineBinaryDedicatedTests(tcu::TestContext &testCtx,
1283                                                                 PipelineConstructionType pipelineConstructionType,
1284                                                                 de::MovePtr<tcu::TestCaseGroup> binaryGroup)
1285 {
1286     de::MovePtr<tcu::TestCaseGroup> dedicatedTests(new tcu::TestCaseGroup(testCtx, "dedicated"));
1287     dedicatedTests->addChild(
1288         new BaseTestCase(testCtx, "unique_key_pairs", {pipelineConstructionType, TestType::UNIQUE_KEY_PAIRS, false}));
1289     dedicatedTests->addChild(
1290         new BaseTestCase(testCtx, "graphics_pipeline_from_internal_cache",
1291                          {pipelineConstructionType, TestType::GRAPHICS_PIPELINE_FROM_INTERNAL_CACHE, false}));
1292 
1293     if (pipelineConstructionType == PipelineConstructionType::PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1294     {
1295         dedicatedTests->addChild(new BaseTestCase(testCtx, "create_incomplete",
1296                                                   {pipelineConstructionType, TestType::CREATE_INCOMPLETE, false}));
1297         dedicatedTests->addChild(new BaseTestCase(testCtx, "not_enough_space",
1298                                                   {pipelineConstructionType, TestType::NOT_ENOUGH_SPACE, false}));
1299         dedicatedTests->addChild(new BaseTestCase(testCtx, "destroy_null_binary",
1300                                                   {pipelineConstructionType, TestType::DESTROY_NULL_BINARY, false}));
1301         dedicatedTests->addChild(
1302             new BaseTestCase(testCtx, "compute_pipeline_with_zero_binary_count",
1303                              {pipelineConstructionType, TestType::CREATE_WITH_ZERO_BINARY_COUNT, false}));
1304         dedicatedTests->addChild(
1305             new BaseTestCase(testCtx, "compute_pipeline_from_internal_cache",
1306                              {pipelineConstructionType, TestType::COMPUTE_PIPELINE_FROM_INTERNAL_CACHE, false}));
1307 
1308         dedicatedTests->addChild(
1309             new BaseTestCase(testCtx, "graphics_pipeline_with_zero_binary_count",
1310                              {pipelineConstructionType, TestType::GRAPHICS_PIPELINE_WITH_ZERO_BINARY_COUNT, false}));
1311 
1312         dedicatedTests->addChild(
1313             new BaseTestCase(testCtx, "ray_tracing_pipeline_from_internal_cache",
1314                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE, false}));
1315         dedicatedTests->addChild(
1316             new BaseTestCase(testCtx, "ray_tracing_pipeline_from_pipeline",
1317                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE, false}));
1318         dedicatedTests->addChild(
1319             new BaseTestCase(testCtx, "ray_tracing_pipeline_from_binary_data",
1320                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA, false}));
1321 
1322         dedicatedTests->addChild(
1323             new BaseTestCase(testCtx, "ray_tracing_pipeline_library_from_internal_cache",
1324                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_INTERNAL_CACHE, true}));
1325         dedicatedTests->addChild(
1326             new BaseTestCase(testCtx, "ray_tracing_pipeline_library_from_pipeline",
1327                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_PIPELINE, true}));
1328         dedicatedTests->addChild(
1329             new BaseTestCase(testCtx, "ray_tracing_pipeline_library_from_binary_data",
1330                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_FROM_BINARY_DATA, true}));
1331         dedicatedTests->addChild(
1332             new BaseTestCase(testCtx, "ray_tracing_pipeline_with_zero_binary_count",
1333                              {pipelineConstructionType, TestType::RAY_TRACING_PIPELINE_WITH_ZERO_BINARY_COUNT, true}));
1334     }
1335 
1336     binaryGroup->addChild(dedicatedTests.release());
1337     return binaryGroup;
1338 }
1339 
1340 } // namespace vkt::pipeline
1341