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, ©Region);
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