xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/pipeline/vktPipelineBindPointTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Pipeline Bind Point Tests
25  *//*--------------------------------------------------------------------*/
26 #include "vktPipelineBindPointTests.hpp"
27 #include "vktPipelineImageUtil.hpp"
28 
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkBufferWithMemory.hpp"
36 #include "vkImageWithMemory.hpp"
37 #include "vkRayTracingUtil.hpp"
38 
39 #include "tcuVector.hpp"
40 
41 #include <algorithm>
42 #include <string>
43 #include <sstream>
44 #include <type_traits>
45 #include <utility>
46 
47 namespace vkt
48 {
49 namespace pipeline
50 {
51 
52 namespace
53 {
54 
55 using namespace vk;
56 
57 // These operations will be tried in different orders.
58 // To avoid combinatory explosions, we'll only use two pipeline types per test, which means 2 pipeline bind operations and 2 related set bind operations.
59 // The following types will be mixed: (graphics, compute), (graphics, ray tracing) and (compute, ray tracing).
60 enum class SetupOp
61 {
62     BIND_GRAPHICS_PIPELINE   = 0,
63     BIND_COMPUTE_PIPELINE    = 1,
64     BIND_RAYTRACING_PIPELINE = 2,
65     BIND_GRAPHICS_SET        = 3,
66     BIND_COMPUTE_SET         = 4,
67     BIND_RAYTRACING_SET      = 5,
68     OP_COUNT                 = 6,
69 };
70 
71 // How to bind each set.
72 enum class SetUpdateType
73 {
74     WRITE              = 0,
75     PUSH               = 1,
76     PUSH_WITH_TEMPLATE = 2,
77     TYPE_COUNT         = 3,
78 };
79 
80 // Types of operations to dispatch. They will be tried in different orders and are related to the setup sequence.
81 enum class DispatchOp
82 {
83     DRAW       = 0,
84     COMPUTE    = 1,
85     TRACE_RAYS = 2,
86     OP_COUNT   = 3,
87 };
88 
89 constexpr auto kTestBindPoints    = 2;                   // Two bind points per test.
90 constexpr auto kSetupSequenceSize = kTestBindPoints * 2; // For each bind point: bind pipeline and bind set.
91 constexpr auto kDispatchSequenceSize =
92     kTestBindPoints; // Dispatch two types of work, matching the bind points being used.
93 
94 using SetupSequence    = tcu::Vector<SetupOp, kSetupSequenceSize>;
95 using DispatchSequence = tcu::Vector<DispatchOp, kDispatchSequenceSize>;
96 
97 // Test parameters.
98 struct TestParams
99 {
100     PipelineConstructionType pipelineConstructionType;
101     SetUpdateType graphicsSetUpdateType;
102     SetUpdateType computeSetUpdateType;
103     SetUpdateType rayTracingSetUpdateType;
104     SetupSequence setupSequence;
105     DispatchSequence dispatchSequence;
106 
107 protected:
hasSetupOpvkt::pipeline::__anond8c5aeff0111::TestParams108     bool hasSetupOp(SetupOp op) const
109     {
110         for (int i = 0; i < decltype(setupSequence)::SIZE; ++i)
111         {
112             if (setupSequence[i] == op)
113                 return true;
114         }
115         return false;
116     }
117 
hasAnyOfvkt::pipeline::__anond8c5aeff0111::TestParams118     bool hasAnyOf(const std::vector<SetupOp> &opVec) const
119     {
120         for (const auto &op : opVec)
121         {
122             if (hasSetupOp(op))
123                 return true;
124         }
125         return false;
126     }
127 
128 public:
hasGraphicsvkt::pipeline::__anond8c5aeff0111::TestParams129     bool hasGraphics(void) const
130     {
131         const std::vector<SetupOp> setupOps{SetupOp::BIND_GRAPHICS_PIPELINE, SetupOp::BIND_GRAPHICS_SET};
132         return hasAnyOf(setupOps);
133     }
134 
hasComputevkt::pipeline::__anond8c5aeff0111::TestParams135     bool hasCompute(void) const
136     {
137         const std::vector<SetupOp> setupOps{SetupOp::BIND_COMPUTE_PIPELINE, SetupOp::BIND_COMPUTE_SET};
138         return hasAnyOf(setupOps);
139     }
140 
hasRayTracingvkt::pipeline::__anond8c5aeff0111::TestParams141     bool hasRayTracing(void) const
142     {
143         const std::vector<SetupOp> setupOps{SetupOp::BIND_RAYTRACING_PIPELINE, SetupOp::BIND_RAYTRACING_SET};
144         return hasAnyOf(setupOps);
145     }
146 };
147 
148 // Expected output values in each buffer.
149 constexpr uint32_t kExpectedBufferValueGraphics   = 1u;
150 constexpr uint32_t kExpectedBufferValueCompute    = 2u;
151 constexpr uint32_t kExpectedBufferValueRayTracing = 3u;
152 
153 class BindPointTest : public vkt::TestCase
154 {
155 public:
156     BindPointTest(tcu::TestContext &testCtx, const std::string &name, const TestParams &params);
~BindPointTest(void)157     virtual ~BindPointTest(void)
158     {
159     }
160 
161     virtual void checkSupport(Context &context) const;
162     virtual void initPrograms(vk::SourceCollections &programCollection) const;
163     virtual TestInstance *createInstance(Context &context) const;
164 
165 protected:
166     TestParams m_params;
167 };
168 
169 class BindPointInstance : public vkt::TestInstance
170 {
171 public:
172     BindPointInstance(Context &context, const TestParams &params);
~BindPointInstance(void)173     virtual ~BindPointInstance(void)
174     {
175     }
176 
177     virtual tcu::TestStatus iterate(void);
178 
179 protected:
180     TestParams m_params;
181 };
182 
BindPointTest(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)183 BindPointTest::BindPointTest(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
184     : vkt::TestCase(testCtx, name)
185     , m_params(params)
186 {
187 }
188 
checkSupport(Context & context) const189 void BindPointTest::checkSupport(Context &context) const
190 {
191     if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType != SetUpdateType::WRITE) ||
192         (m_params.hasCompute() && m_params.computeSetUpdateType != SetUpdateType::WRITE) ||
193         (m_params.hasRayTracing() && m_params.rayTracingSetUpdateType != SetUpdateType::WRITE))
194     {
195         context.requireDeviceFunctionality("VK_KHR_push_descriptor");
196 
197         if ((m_params.hasGraphics() && m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
198             (m_params.hasCompute() && m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) ||
199             (m_params.hasRayTracing() && m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE))
200         {
201             context.requireDeviceFunctionality("VK_KHR_descriptor_update_template");
202         }
203     }
204 
205     if (m_params.hasRayTracing())
206         context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
207 
208     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
209                                           m_params.pipelineConstructionType);
210 }
211 
initPrograms(vk::SourceCollections & programCollection) const212 void BindPointTest::initPrograms(vk::SourceCollections &programCollection) const
213 {
214     // The flags array will only have 1 element.
215     const std::string descriptorDecl =
216         "layout(set=0, binding=0, std430) buffer BufferBlock { uint flag[]; } outBuffer;\n";
217 
218     if (m_params.hasGraphics())
219     {
220         std::ostringstream vert;
221         vert << "#version 450\n"
222              << "\n"
223              << "void main()\n"
224              << "{\n"
225              // Full-screen clockwise triangle strip with 4 vertices.
226              << "    const float x = (-1.0+2.0*((gl_VertexIndex & 2)>>1));\n"
227              << "    const float y = ( 1.0-2.0* (gl_VertexIndex % 2));\n"
228              << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
229              << "}\n";
230 
231         // Note: the color attachment will be a 1x1 image, so gl_FragCoord.xy is (0.5, 0.5).
232         std::ostringstream frag;
233         frag << "#version 450\n"
234              << descriptorDecl << "layout(location=0) out vec4 outColor;\n"
235              << "\n"
236              << "void main()\n"
237              << "{\n"
238              << "  const uint xCoord = uint(trunc(gl_FragCoord.x));\n"
239              << "  const uint yCoord = uint(trunc(gl_FragCoord.y));\n"
240              << "  outBuffer.flag[xCoord + yCoord] = " << kExpectedBufferValueGraphics << "u;\n"
241              << "  outColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
242              << "}\n";
243 
244         programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
245         programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
246     }
247 
248     if (m_params.hasCompute())
249     {
250         // Note: we will only dispatch 1 group.
251         std::ostringstream comp;
252         comp << "#version 450\n"
253              << descriptorDecl << "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
254              << "\n"
255              << "void main()\n"
256              << "{\n"
257              << "  const uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y + gl_GlobalInvocationID.z;\n"
258              << "  outBuffer.flag[index] = " << kExpectedBufferValueCompute << "u;\n"
259              << "}\n";
260 
261         programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
262     }
263 
264     if (m_params.hasRayTracing())
265     {
266         // We will only call the ray gen shader once.
267         std::ostringstream rgen;
268         rgen << "#version 460\n"
269              << "#extension GL_EXT_ray_tracing : require\n"
270              << descriptorDecl << "\n"
271              << "void main()\n"
272              << "{\n"
273              << "  const uint index = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y + gl_LaunchIDEXT.z;\n"
274              << "  outBuffer.flag[index] = " << kExpectedBufferValueRayTracing << "u;\n"
275              << "}\n";
276 
277         const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
278         programCollection.glslSources.add("rgen")
279             << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
280     }
281 }
282 
createInstance(Context & context) const283 vkt::TestInstance *BindPointTest::createInstance(Context &context) const
284 {
285     return new BindPointInstance(context, m_params);
286 }
287 
BindPointInstance(Context & context,const TestParams & params)288 BindPointInstance::BindPointInstance(Context &context, const TestParams &params)
289     : vkt::TestInstance(context)
290     , m_params(params)
291 {
292 }
293 
makeSetLayout(const DeviceInterface & vkd,VkDevice device,VkShaderStageFlags stages,bool push)294 Move<VkDescriptorSetLayout> makeSetLayout(const DeviceInterface &vkd, VkDevice device, VkShaderStageFlags stages,
295                                           bool push)
296 {
297     VkDescriptorSetLayoutCreateFlags createFlags = 0u;
298     if (push)
299         createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
300 
301     DescriptorSetLayoutBuilder builder;
302     builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages);
303     return builder.build(vkd, device, createFlags);
304 }
305 
zeroOutAndFlush(const DeviceInterface & vkd,VkDevice device,BufferWithMemory & buffer,VkDeviceSize bufferSize)306 void zeroOutAndFlush(const DeviceInterface &vkd, VkDevice device, BufferWithMemory &buffer, VkDeviceSize bufferSize)
307 {
308     auto &alloc   = buffer.getAllocation();
309     void *hostPtr = alloc.getHostPtr();
310 
311     deMemset(hostPtr, 0, static_cast<size_t>(bufferSize));
312     flushAlloc(vkd, device, alloc);
313 }
314 
makePoolAndSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorSetLayout layout,Move<VkDescriptorPool> & pool,Move<VkDescriptorSet> & set)315 void makePoolAndSet(const DeviceInterface &vkd, VkDevice device, VkDescriptorSetLayout layout,
316                     Move<VkDescriptorPool> &pool, Move<VkDescriptorSet> &set)
317 {
318     DescriptorPoolBuilder poolBuilder;
319     poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
320     pool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
321     set  = makeDescriptorSet(vkd, device, pool.get(), layout);
322 }
323 
writeSetUpdate(const DeviceInterface & vkd,VkDevice device,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size,VkDescriptorSet set)324 void writeSetUpdate(const DeviceInterface &vkd, VkDevice device, VkBuffer buffer, VkDeviceSize offset,
325                     VkDeviceSize size, VkDescriptorSet set)
326 {
327     DescriptorSetUpdateBuilder updateBuilder;
328     const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size);
329     updateBuilder.writeSingle(set, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
330                               &bufferInfo);
331     updateBuilder.update(vkd, device);
332 }
333 
makeUpdateTemplate(const DeviceInterface & vkd,VkDevice device,VkDescriptorSetLayout setLayout,VkPipelineBindPoint bindPoint,VkPipelineLayout pipelineLayout)334 Move<VkDescriptorUpdateTemplate> makeUpdateTemplate(const DeviceInterface &vkd, VkDevice device,
335                                                     VkDescriptorSetLayout setLayout, VkPipelineBindPoint bindPoint,
336                                                     VkPipelineLayout pipelineLayout)
337 {
338     const auto templateEntry =
339         makeDescriptorUpdateTemplateEntry(0u, 0u, 1u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast<uintptr_t>(0),
340                                           static_cast<uintptr_t>(sizeof(VkDescriptorBufferInfo)));
341     const VkDescriptorUpdateTemplateCreateInfo templateCreateInfo = {
342         VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, // VkStructureType sType;
343         nullptr,                                                  // const void* pNext;
344         0u,                                                       // VkDescriptorUpdateTemplateCreateFlags flags;
345         1u,                                                       // uint32_t descriptorUpdateEntryCount;
346         &templateEntry, // const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries;
347         VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR, // VkDescriptorUpdateTemplateType templateType;
348         setLayout,                                               // VkDescriptorSetLayout descriptorSetLayout;
349         bindPoint,                                               // VkPipelineBindPoint pipelineBindPoint;
350         pipelineLayout,                                          // VkPipelineLayout pipelineLayout;
351         0u,                                                      // uint32_t set;
352     };
353     return createDescriptorUpdateTemplate(vkd, device, &templateCreateInfo);
354 }
355 
pushBufferDescriptor(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,VkPipelineBindPoint bindPoint,VkPipelineLayout layout,VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size)356 void pushBufferDescriptor(const DeviceInterface &vkd, VkCommandBuffer cmdBuffer, VkPipelineBindPoint bindPoint,
357                           VkPipelineLayout layout, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
358 {
359     const auto bufferInfo            = makeDescriptorBufferInfo(buffer, offset, size);
360     const VkWriteDescriptorSet write = {
361         VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
362         nullptr,                                // const void* pNext;
363         DE_NULL,                                // VkDescriptorSet dstSet;
364         0u,                                     // uint32_t dstBinding;
365         0u,                                     // uint32_t dstArrayElement;
366         1u,                                     // uint32_t descriptorCount;
367         VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,      // VkDescriptorType descriptorType;
368         nullptr,                                // const VkDescriptorImageInfo* pImageInfo;
369         &bufferInfo,                            // const VkDescriptorBufferInfo* pBufferInfo;
370         nullptr,                                // const VkBufferView* pTexelBufferView;
371     };
372     vkd.cmdPushDescriptorSetKHR(cmdBuffer, bindPoint, layout, 0u, 1u, &write);
373 }
374 
verifyBufferContents(const DeviceInterface & vkd,VkDevice device,const BufferWithMemory & buffer,const std::string & bufferName,uint32_t expected)375 void verifyBufferContents(const DeviceInterface &vkd, VkDevice device, const BufferWithMemory &buffer,
376                           const std::string &bufferName, uint32_t expected)
377 {
378     auto &bufferAlloc  = buffer.getAllocation();
379     const auto dataPtr = reinterpret_cast<uint32_t *>(bufferAlloc.getHostPtr());
380     uint32_t data;
381 
382     invalidateAlloc(vkd, device, bufferAlloc);
383     deMemcpy(&data, dataPtr, sizeof(data));
384 
385     if (data != expected)
386     {
387         std::ostringstream msg;
388         msg << "Invalid value found in " << bufferName << " buffer: expected " << expected << " and found " << data;
389         TCU_FAIL(msg.str());
390     }
391 }
392 
makeBufferBarrier(VkBuffer buffer,VkDeviceSize offset,VkDeviceSize size)393 VkBufferMemoryBarrier makeBufferBarrier(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)
394 {
395     return makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, offset, size);
396 }
397 
recordBufferBarrier(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,VkPipelineStageFlagBits stage,const VkBufferMemoryBarrier & barrier)398 void recordBufferBarrier(const DeviceInterface &vkd, VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits stage,
399                          const VkBufferMemoryBarrier &barrier)
400 {
401     vkd.cmdPipelineBarrier(cmdBuffer, stage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr);
402 }
403 
iterate(void)404 tcu::TestStatus BindPointInstance::iterate(void)
405 {
406     const auto &vki    = m_context.getInstanceInterface();
407     const auto physDev = m_context.getPhysicalDevice();
408     const auto &vkd    = m_context.getDeviceInterface();
409     const auto device  = m_context.getDevice();
410     const auto qIndex  = m_context.getUniversalQueueFamilyIndex();
411     const auto queue   = m_context.getUniversalQueue();
412     auto &alloc        = m_context.getDefaultAllocator();
413 
414     const auto imageFormat   = VK_FORMAT_R8G8B8A8_UNORM;
415     const auto imageExtent   = makeExtent3D(1u, 1u, 1u);
416     const auto imageType     = VK_IMAGE_TYPE_2D;
417     const auto imageViewType = VK_IMAGE_VIEW_TYPE_2D;
418     const auto imageUsage =
419         static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
420 
421     const std::vector<VkViewport> viewports{makeViewport(imageExtent)};
422     const std::vector<VkRect2D> scissors{makeRect2D(imageExtent)};
423 
424     const auto hasGraphics   = m_params.hasGraphics();
425     const auto hasCompute    = m_params.hasCompute();
426     const auto hasRayTracing = m_params.hasRayTracing();
427 
428     // Storage buffers.
429     const auto bufferSize       = static_cast<VkDeviceSize>(sizeof(uint32_t));
430     const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
431 
432     using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
433     using ImageWithMemoryPtr  = de::MovePtr<ImageWithMemory>;
434 
435     BufferWithMemoryPtr graphicsBuffer;
436     BufferWithMemoryPtr computeBuffer;
437     BufferWithMemoryPtr rayTracingBuffer;
438 
439     if (hasGraphics)
440         graphicsBuffer = BufferWithMemoryPtr(
441             new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
442     if (hasCompute)
443         computeBuffer = BufferWithMemoryPtr(
444             new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
445     if (hasRayTracing)
446         rayTracingBuffer = BufferWithMemoryPtr(
447             new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
448 
449     if (hasGraphics)
450         zeroOutAndFlush(vkd, device, *graphicsBuffer, bufferSize);
451     if (hasCompute)
452         zeroOutAndFlush(vkd, device, *computeBuffer, bufferSize);
453     if (hasRayTracing)
454         zeroOutAndFlush(vkd, device, *rayTracingBuffer, bufferSize);
455 
456     ImageWithMemoryPtr colorAttachment;
457     Move<VkImageView> colorAttachmentView;
458 
459     if (hasGraphics)
460     {
461         // Color attachment.
462         const VkImageCreateInfo imageCreateInfo = {
463             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
464             nullptr,                             // const void* pNext;
465             0u,                                  // VkImageCreateFlags flags;
466             imageType,                           // VkImageType imageType;
467             imageFormat,                         // VkFormat format;
468             imageExtent,                         // VkExtent3D extent;
469             1u,                                  // uint32_t mipLevels;
470             1u,                                  // uint32_t arrayLayers;
471             VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
472             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
473             imageUsage,                          // VkImageUsageFlags usage;
474             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
475             1u,                                  // uint32_t queueFamilyIndexCount;
476             &qIndex,                             // const uint32_t* pQueueFamilyIndices;
477             VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
478         };
479 
480         const auto subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
481         colorAttachment =
482             ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
483         colorAttachmentView =
484             makeImageView(vkd, device, colorAttachment->get(), imageViewType, imageFormat, subresourceRange);
485     }
486 
487     // Command buffer and pool.
488     const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
489     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
490     const auto cmdBuffer    = cmdBufferPtr.get();
491 
492     // Set and pipeline layouts.
493     Move<VkDescriptorSetLayout> graphicsSetLayout;
494     Move<VkDescriptorSetLayout> computeSetLayout;
495     Move<VkDescriptorSetLayout> rayTracingSetLayout;
496 
497     if (hasGraphics)
498         graphicsSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_FRAGMENT_BIT,
499                                           (m_params.graphicsSetUpdateType != SetUpdateType::WRITE));
500     if (hasCompute)
501         computeSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_COMPUTE_BIT,
502                                          (m_params.computeSetUpdateType != SetUpdateType::WRITE));
503     if (hasRayTracing)
504         rayTracingSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_RAYGEN_BIT_KHR,
505                                             (m_params.rayTracingSetUpdateType != SetUpdateType::WRITE));
506 
507     PipelineLayoutWrapper graphicsPipelineLayout;
508     PipelineLayoutWrapper computePipelineLayout;
509     PipelineLayoutWrapper rayTracingPipelineLayout;
510 
511     if (hasGraphics)
512         graphicsPipelineLayout =
513             PipelineLayoutWrapper(m_params.pipelineConstructionType, vkd, device, graphicsSetLayout.get());
514     if (hasCompute)
515         computePipelineLayout =
516             PipelineLayoutWrapper(m_params.pipelineConstructionType, vkd, device, computeSetLayout.get());
517     if (hasRayTracing)
518         rayTracingPipelineLayout =
519             PipelineLayoutWrapper(m_params.pipelineConstructionType, vkd, device, rayTracingSetLayout.get());
520 
521     // Shader modules.
522     ShaderWrapper vertShader;
523     ShaderWrapper fragShader;
524     ShaderWrapper compShader;
525     ShaderWrapper rgenShader;
526 
527     if (hasGraphics)
528         vertShader = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
529     if (hasGraphics)
530         fragShader = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
531     if (hasCompute)
532         compShader = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("comp"), 0u);
533     if (hasRayTracing)
534         rgenShader = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("rgen"), 0u);
535 
536     RenderPassWrapper renderPass;
537     GraphicsPipelineWrapper graphicsPipeline(vki, vkd, physDev, device, m_context.getDeviceExtensions(),
538                                              m_params.pipelineConstructionType);
539 
540     if (hasGraphics)
541     {
542         // Render pass and framebuffer.
543         renderPass = RenderPassWrapper(m_params.pipelineConstructionType, vkd, device, imageFormat);
544         renderPass.createFramebuffer(vkd, device, **colorAttachment, colorAttachmentView.get(), imageExtent.width,
545                                      imageExtent.height);
546 
547         // Graphics pipeline.
548         const VkPipelineVertexInputStateCreateInfo vertexInputState = {
549             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                             sType
550             nullptr, // const void*                                 pNext
551             0u,      // VkPipelineVertexInputStateCreateFlags       flags
552             0u,      // uint32_t                                    vertexBindingDescriptionCount
553             nullptr, // const VkVertexInputBindingDescription*      pVertexBindingDescriptions
554             0u,      // uint32_t                                    vertexAttributeDescriptionCount
555             nullptr, // const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
556         };
557 
558         graphicsPipeline.setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
559             .setDefaultRasterizationState()
560             .setDefaultMultisampleState()
561             .setDefaultDepthStencilState()
562             .setDefaultColorBlendState()
563             .setupVertexInputState(&vertexInputState)
564             .setupPreRasterizationShaderState(viewports, scissors, graphicsPipelineLayout, *renderPass, 0u, vertShader)
565             .setupFragmentShaderState(graphicsPipelineLayout, *renderPass, 0u, fragShader)
566             .setupFragmentOutputState(*renderPass, 0u)
567             .setMonolithicPipelineLayout(graphicsPipelineLayout)
568             .buildPipeline();
569     }
570 
571     // Compute pipeline.
572     Move<VkPipeline> computePipeline;
573 
574     if (hasCompute)
575     {
576         const VkPipelineShaderStageCreateInfo computeShaderStageInfo = {
577             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
578             nullptr,                                             // const void* pNext;
579             0u,                                                  // VkPipelineShaderStageCreateFlags flags;
580             VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
581             compShader.getModule(),                              // VkShaderModule module;
582             "main",                                              // const char* pName;
583             nullptr,                                             // const VkSpecializationInfo* pSpecializationInfo;
584         };
585 
586         const VkComputePipelineCreateInfo computePipelineCreateInfo = {
587             VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
588             nullptr,                                        // const void* pNext;
589             0u,                                             // VkPipelineCreateFlags flags;
590             computeShaderStageInfo,                         // VkPipelineShaderStageCreateInfo stage;
591             computePipelineLayout.get(),                    // VkPipelineLayout layout;
592             DE_NULL,                                        // VkPipeline basePipelineHandle;
593             0u,                                             // int32_t basePipelineIndex;
594         };
595 
596         computePipeline = createComputePipeline(vkd, device, DE_NULL, &computePipelineCreateInfo);
597     }
598 
599     // Ray tracing pipeline and shader binding tables.
600     using RayTracingPipelineHelperPtr = de::MovePtr<RayTracingPipeline>;
601 
602     RayTracingPipelineHelperPtr rayTracingPipelineHelper;
603     Move<VkPipeline> rayTracingPipeline;
604     BufferWithMemoryPtr raygenSBT;
605 
606     VkStridedDeviceAddressRegionKHR raygenSBTRegion   = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
607     VkStridedDeviceAddressRegionKHR missSBTRegion     = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
608     VkStridedDeviceAddressRegionKHR hitSBTRegion      = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
609     VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
610 
611     if (hasRayTracing)
612     {
613         const auto rtProperties             = makeRayTracingProperties(vki, physDev);
614         const auto shaderGroupHandleSize    = rtProperties->getShaderGroupHandleSize();
615         const auto shaderGroupBaseAlignment = rtProperties->getShaderGroupBaseAlignment();
616         rayTracingPipelineHelper            = RayTracingPipelineHelperPtr(new RayTracingPipeline());
617 
618         rayTracingPipelineHelper->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenShader.getModule(), 0);
619         rayTracingPipeline = rayTracingPipelineHelper->createPipeline(vkd, device, rayTracingPipelineLayout.get());
620 
621         raygenSBT = rayTracingPipelineHelper->createShaderBindingTable(
622             vkd, device, rayTracingPipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
623         raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0),
624                                                             shaderGroupHandleSize, shaderGroupHandleSize);
625     }
626 
627     // Descriptor pools and sets if needed.
628     Move<VkDescriptorPool> graphicsDescriptorPool;
629     Move<VkDescriptorPool> computeDescriptorPool;
630     Move<VkDescriptorPool> rayTracingDescriptorPool;
631     Move<VkDescriptorSet> graphicsDescritorSet;
632     Move<VkDescriptorSet> computeDescriptorSet;
633     Move<VkDescriptorSet> rayTracingDescriptorSet;
634 
635     if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
636     {
637         makePoolAndSet(vkd, device, graphicsSetLayout.get(), graphicsDescriptorPool, graphicsDescritorSet);
638         writeSetUpdate(vkd, device, graphicsBuffer->get(), 0ull, bufferSize, graphicsDescritorSet.get());
639     }
640 
641     if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
642     {
643         makePoolAndSet(vkd, device, computeSetLayout.get(), computeDescriptorPool, computeDescriptorSet);
644         writeSetUpdate(vkd, device, computeBuffer->get(), 0ull, bufferSize, computeDescriptorSet.get());
645     }
646 
647     if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
648     {
649         makePoolAndSet(vkd, device, rayTracingSetLayout.get(), rayTracingDescriptorPool, rayTracingDescriptorSet);
650         writeSetUpdate(vkd, device, rayTracingBuffer->get(), 0ull, bufferSize, rayTracingDescriptorSet.get());
651     }
652 
653     // Templates if needed.
654     Move<VkDescriptorUpdateTemplate> graphicsUpdateTemplate;
655     Move<VkDescriptorUpdateTemplate> computeUpdateTemplate;
656     Move<VkDescriptorUpdateTemplate> rayTracingUpdateTemplate;
657 
658     if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
659         graphicsUpdateTemplate = makeUpdateTemplate(vkd, device, graphicsSetLayout.get(),
660                                                     VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get());
661 
662     if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
663         computeUpdateTemplate = makeUpdateTemplate(vkd, device, computeSetLayout.get(), VK_PIPELINE_BIND_POINT_COMPUTE,
664                                                    computePipelineLayout.get());
665 
666     if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
667         rayTracingUpdateTemplate =
668             makeUpdateTemplate(vkd, device, rayTracingSetLayout.get(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
669                                rayTracingPipelineLayout.get());
670 
671     beginCommandBuffer(vkd, cmdBuffer);
672 
673     // Helper flags to check the test has been specified properly.
674     bool boundGraphicsPipeline   = false;
675     bool boundGraphicsSet        = false;
676     bool boundComputePipeline    = false;
677     bool boundComputeSet         = false;
678     bool boundRayTracingPipeline = false;
679     bool boundRayTracingSet      = false;
680 
681     // Setup operations in desired order.
682     for (int i = 0; i < decltype(m_params.setupSequence)::SIZE; ++i)
683     {
684         const auto &setupOp = m_params.setupSequence[i];
685         switch (setupOp)
686         {
687         case SetupOp::BIND_GRAPHICS_PIPELINE:
688             graphicsPipeline.bind(cmdBuffer);
689             boundGraphicsPipeline = true;
690             break;
691 
692         case SetupOp::BIND_COMPUTE_PIPELINE:
693             vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get());
694             boundComputePipeline = true;
695             break;
696 
697         case SetupOp::BIND_RAYTRACING_PIPELINE:
698             vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipeline.get());
699             boundRayTracingPipeline = true;
700             break;
701 
702         case SetupOp::BIND_GRAPHICS_SET:
703             if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE)
704                 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), 0u,
705                                           1u, &graphicsDescritorSet.get(), 0u, nullptr);
706             else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH)
707                 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(),
708                                      graphicsBuffer->get(), 0ull, bufferSize);
709             else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
710             {
711                 const auto bufferInfo = makeDescriptorBufferInfo(graphicsBuffer->get(), 0ull, bufferSize);
712                 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, graphicsUpdateTemplate.get(),
713                                                         graphicsPipelineLayout.get(), 0u, &bufferInfo);
714             }
715             else
716                 DE_ASSERT(false);
717             boundGraphicsSet = true;
718             break;
719 
720         case SetupOp::BIND_COMPUTE_SET:
721             if (m_params.computeSetUpdateType == SetUpdateType::WRITE)
722                 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), 0u,
723                                           1u, &computeDescriptorSet.get(), 0u, nullptr);
724             else if (m_params.computeSetUpdateType == SetUpdateType::PUSH)
725                 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(),
726                                      computeBuffer->get(), 0ull, bufferSize);
727             else if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
728             {
729                 const auto bufferInfo = makeDescriptorBufferInfo(computeBuffer->get(), 0ull, bufferSize);
730                 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, computeUpdateTemplate.get(),
731                                                         computePipelineLayout.get(), 0u, &bufferInfo);
732             }
733             else
734                 DE_ASSERT(false);
735             boundComputeSet = true;
736             break;
737 
738         case SetupOp::BIND_RAYTRACING_SET:
739             if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE)
740                 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
741                                           rayTracingPipelineLayout.get(), 0u, 1u, &rayTracingDescriptorSet.get(), 0u,
742                                           nullptr);
743             else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH)
744                 pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR,
745                                      rayTracingPipelineLayout.get(), rayTracingBuffer->get(), 0ull, bufferSize);
746             else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE)
747             {
748                 const auto bufferInfo = makeDescriptorBufferInfo(rayTracingBuffer->get(), 0ull, bufferSize);
749                 vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, rayTracingUpdateTemplate.get(),
750                                                         rayTracingPipelineLayout.get(), 0u, &bufferInfo);
751             }
752             else
753                 DE_ASSERT(false);
754             boundRayTracingSet = true;
755             break;
756 
757         default:
758             DE_ASSERT(false);
759             break;
760         }
761     }
762 
763     // Avoid warning in release builds.
764     DE_UNREF(boundGraphicsPipeline);
765     DE_UNREF(boundGraphicsSet);
766     DE_UNREF(boundComputePipeline);
767     DE_UNREF(boundComputeSet);
768     DE_UNREF(boundRayTracingPipeline);
769     DE_UNREF(boundRayTracingSet);
770 
771     // Dispatch operations in desired order.
772     for (int i = 0; i < decltype(m_params.dispatchSequence)::SIZE; ++i)
773     {
774         const auto &dispatchOp = m_params.dispatchSequence[i];
775         switch (dispatchOp)
776         {
777         case DispatchOp::DRAW:
778             DE_ASSERT(boundGraphicsPipeline && boundGraphicsSet);
779             renderPass.begin(vkd, cmdBuffer, scissors[0], tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
780             vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u);
781             renderPass.end(vkd, cmdBuffer);
782             break;
783 
784         case DispatchOp::COMPUTE:
785             DE_ASSERT(boundComputePipeline && boundComputeSet);
786             vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
787             break;
788 
789         case DispatchOp::TRACE_RAYS:
790             DE_ASSERT(boundRayTracingPipeline && boundRayTracingSet);
791             cmdTraceRays(vkd, cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u,
792                          1u);
793             break;
794 
795         default:
796             DE_ASSERT(false);
797             break;
798         }
799     }
800 
801     if (hasGraphics)
802     {
803         const auto graphicsBufferBarrier = makeBufferBarrier(graphicsBuffer->get(), 0ull, bufferSize);
804         recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, graphicsBufferBarrier);
805     }
806     if (hasCompute)
807     {
808         const auto computeBufferBarrier = makeBufferBarrier(computeBuffer->get(), 0ull, bufferSize);
809         recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, computeBufferBarrier);
810     }
811     if (hasRayTracing)
812     {
813         const auto rayTracingBufferBarrier = makeBufferBarrier(rayTracingBuffer->get(), 0ull, bufferSize);
814         recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, rayTracingBufferBarrier);
815     }
816 
817     endCommandBuffer(vkd, cmdBuffer);
818     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
819 
820     // Verify storage buffers.
821     if (hasGraphics)
822         verifyBufferContents(vkd, device, *graphicsBuffer, "graphics", kExpectedBufferValueGraphics);
823     if (hasCompute)
824         verifyBufferContents(vkd, device, *computeBuffer, "compute", kExpectedBufferValueCompute);
825     if (hasRayTracing)
826         verifyBufferContents(vkd, device, *rayTracingBuffer, "raytracing", kExpectedBufferValueRayTracing);
827 
828     // Verify color attachment.
829     if (hasGraphics)
830     {
831         const auto textureLevel = readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment->get(),
832                                                       imageFormat, tcu::UVec2(imageExtent.width, imageExtent.height));
833         const auto pixelBuffer  = textureLevel->getAccess();
834         const auto iWidth       = static_cast<int>(imageExtent.width);
835         const auto iHeight      = static_cast<int>(imageExtent.height);
836         const tcu::Vec4 expectedColor(0.0f, 1.0f, 0.0f, 1.0f);
837 
838         for (int y = 0; y < iHeight; ++y)
839             for (int x = 0; x < iWidth; ++x)
840             {
841                 const auto value = pixelBuffer.getPixel(x, y);
842                 if (value != expectedColor)
843                 {
844                     std::ostringstream msg;
845                     msg << "Unexpected color found in attachment: expected " << expectedColor << " but found " << value;
846                     TCU_FAIL(msg.str());
847                 }
848             }
849     }
850 
851     return tcu::TestStatus::pass("Pass");
852 }
853 
854 // Auxiliar string conversion functions.
855 
toString(SetUpdateType updateType)856 std::string toString(SetUpdateType updateType)
857 {
858     switch (updateType)
859     {
860     case SetUpdateType::WRITE:
861         return "write";
862     case SetUpdateType::PUSH:
863         return "push";
864     case SetUpdateType::PUSH_WITH_TEMPLATE:
865         return "template_push";
866     default:
867         DE_ASSERT(false);
868         break;
869     }
870 
871     return "";
872 }
873 
toString(const SetupSequence & setupSequence)874 std::string toString(const SetupSequence &setupSequence)
875 {
876     std::ostringstream out;
877 
878     out << "setup";
879     for (int i = 0; i < std::remove_reference<decltype(setupSequence)>::type::SIZE; ++i)
880     {
881         out << "_";
882         switch (setupSequence[i])
883         {
884         case SetupOp::BIND_GRAPHICS_PIPELINE:
885             out << "gp";
886             break;
887         case SetupOp::BIND_COMPUTE_PIPELINE:
888             out << "cp";
889             break;
890         case SetupOp::BIND_RAYTRACING_PIPELINE:
891             out << "rp";
892             break;
893         case SetupOp::BIND_GRAPHICS_SET:
894             out << "gs";
895             break;
896         case SetupOp::BIND_COMPUTE_SET:
897             out << "cs";
898             break;
899         case SetupOp::BIND_RAYTRACING_SET:
900             out << "rs";
901             break;
902         default:
903             DE_ASSERT(false);
904             break;
905         }
906     }
907 
908     return out.str();
909 }
910 
toString(const DispatchSequence & dispatchSequence)911 std::string toString(const DispatchSequence &dispatchSequence)
912 {
913     std::ostringstream out;
914 
915     out << "cmd";
916     for (int i = 0; i < std::remove_reference<decltype(dispatchSequence)>::type::SIZE; ++i)
917     {
918         out << "_";
919         switch (dispatchSequence[i])
920         {
921         case DispatchOp::COMPUTE:
922             out << "dispatch";
923             break;
924         case DispatchOp::DRAW:
925             out << "draw";
926             break;
927         case DispatchOp::TRACE_RAYS:
928             out << "tracerays";
929             break;
930         default:
931             DE_ASSERT(false);
932             break;
933         }
934     }
935 
936     return out.str();
937 }
938 
toString(VkPipelineBindPoint point)939 std::string toString(VkPipelineBindPoint point)
940 {
941     if (point == VK_PIPELINE_BIND_POINT_GRAPHICS)
942         return "graphics";
943     if (point == VK_PIPELINE_BIND_POINT_COMPUTE)
944         return "compute";
945     if (point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
946         return "raytracing";
947 
948     DE_ASSERT(false);
949     return "";
950 }
951 
952 } // namespace
953 
createBindPointTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType)954 tcu::TestCaseGroup *createBindPointTests(tcu::TestContext &testCtx, PipelineConstructionType pipelineConstructionType)
955 {
956     using GroupPtr      = de::MovePtr<tcu::TestCaseGroup>;
957     using BindPointPair = tcu::Vector<VkPipelineBindPoint, kTestBindPoints>;
958 
959     GroupPtr bindPointGroup(new tcu::TestCaseGroup(testCtx, "bind_point"));
960 
961     // Bind point combinations to test.
962     const BindPointPair testPairs[] = {
963         BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE),
964         BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
965         BindPointPair(VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR),
966     };
967 
968     for (int testPairIdx = 0; testPairIdx < DE_LENGTH_OF_ARRAY(testPairs); ++testPairIdx)
969     {
970         const auto &testPair = testPairs[testPairIdx];
971 
972         // dont repeat tests if there is no graphics pipeline
973         if (pipelineConstructionType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
974         {
975             bool skipTests = true;
976             for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx)
977             {
978                 if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS)
979                 {
980                     skipTests = false;
981                     break;
982                 }
983             }
984 
985             if (skipTests)
986                 continue;
987         }
988 
989         // Default values. Two of them will be overwritten later.
990         TestParams params;
991         params.pipelineConstructionType = pipelineConstructionType;
992         params.graphicsSetUpdateType    = SetUpdateType::TYPE_COUNT;
993         params.computeSetUpdateType     = SetUpdateType::TYPE_COUNT;
994         params.rayTracingSetUpdateType  = SetUpdateType::TYPE_COUNT;
995 
996         // What to test based on the test pair.
997         // Note: updateTypePtrs will tell us which of the set update type members above we need to vary (graphics, compute, ray tracing).
998         SetUpdateType *updateTypePtrs[kTestBindPoints] = {nullptr, nullptr};
999         SetupOp pipelineBinds[kTestBindPoints]         = {SetupOp::OP_COUNT, SetupOp::OP_COUNT};
1000         SetupOp setBinds[kTestBindPoints]              = {SetupOp::OP_COUNT, SetupOp::OP_COUNT};
1001         DispatchOp dispatches[kTestBindPoints]         = {DispatchOp::OP_COUNT, DispatchOp::OP_COUNT};
1002 
1003         for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx)
1004         {
1005             if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS)
1006             {
1007                 updateTypePtrs[elemIdx] = &params.graphicsSetUpdateType; // Test different graphics set update types.
1008                 pipelineBinds[elemIdx]  = SetupOp::BIND_GRAPHICS_PIPELINE;
1009                 setBinds[elemIdx]       = SetupOp::BIND_GRAPHICS_SET;
1010                 dispatches[elemIdx]     = DispatchOp::DRAW;
1011             }
1012             else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_COMPUTE)
1013             {
1014                 updateTypePtrs[elemIdx] = &params.computeSetUpdateType; // Test different compute set update types.
1015                 pipelineBinds[elemIdx]  = SetupOp::BIND_COMPUTE_PIPELINE;
1016                 setBinds[elemIdx]       = SetupOp::BIND_COMPUTE_SET;
1017                 dispatches[elemIdx]     = DispatchOp::COMPUTE;
1018             }
1019             else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
1020             {
1021                 updateTypePtrs[elemIdx] =
1022                     &params.rayTracingSetUpdateType; // Test different ray tracing set update types.
1023                 pipelineBinds[elemIdx] = SetupOp::BIND_RAYTRACING_PIPELINE;
1024                 setBinds[elemIdx]      = SetupOp::BIND_RAYTRACING_SET;
1025                 dispatches[elemIdx]    = DispatchOp::TRACE_RAYS;
1026             }
1027         }
1028 
1029         const std::string pairName = toString(testPair[0]) + "_" + toString(testPair[1]);
1030         GroupPtr pairGroup(new tcu::TestCaseGroup(testCtx, pairName.c_str()));
1031 
1032         // Combine two update types.
1033         for (int firstUpdateTypeIdx = 0; firstUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT);
1034              ++firstUpdateTypeIdx)
1035             for (int secondUpdateTypeIdx = 0; secondUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT);
1036                  ++secondUpdateTypeIdx)
1037             {
1038                 const auto firstUpdateType        = static_cast<SetUpdateType>(firstUpdateTypeIdx);
1039                 const auto secondUpdateType       = static_cast<SetUpdateType>(secondUpdateTypeIdx);
1040                 const std::string updateGroupName = toString(firstUpdateType) + "_" + toString(secondUpdateType);
1041                 GroupPtr updateGroup(new tcu::TestCaseGroup(testCtx, updateGroupName.c_str()));
1042 
1043                 // Change update types of the relevant sets.
1044                 *updateTypePtrs[0] = firstUpdateType;
1045                 *updateTypePtrs[1] = secondUpdateType;
1046 
1047                 // Prepare initial permutation of test parameters.
1048                 params.setupSequence[0] = pipelineBinds[0];
1049                 params.setupSequence[1] = pipelineBinds[1];
1050                 params.setupSequence[2] = setBinds[0];
1051                 params.setupSequence[3] = setBinds[1];
1052 
1053                 // Permutate setup sequence and dispatch sequence.
1054                 const auto ssBegin = params.setupSequence.m_data;
1055                 const auto ssEnd   = ssBegin + decltype(params.setupSequence)::SIZE;
1056                 do
1057                 {
1058                     const auto setupGroupName = toString(params.setupSequence);
1059                     GroupPtr setupGroup(new tcu::TestCaseGroup(testCtx, setupGroupName.c_str()));
1060 
1061                     // Reset dispatch sequence permutation.
1062                     params.dispatchSequence = dispatches;
1063 
1064                     const auto dsBegin = params.dispatchSequence.m_data;
1065                     const auto dsEnd   = dsBegin + decltype(params.dispatchSequence)::SIZE;
1066                     do
1067                     {
1068                         const auto testName = toString(params.dispatchSequence);
1069                         setupGroup->addChild(new BindPointTest(testCtx, testName, params));
1070                     } while (std::next_permutation(dsBegin, dsEnd));
1071 
1072                     updateGroup->addChild(setupGroup.release());
1073 
1074                 } while (std::next_permutation(ssBegin, ssEnd));
1075 
1076                 pairGroup->addChild(updateGroup.release());
1077             }
1078 
1079         bindPointGroup->addChild(pairGroup.release());
1080     }
1081 
1082     return bindPointGroup.release();
1083 }
1084 
1085 } // namespace pipeline
1086 } // namespace vkt
1087