1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (C) 2022 Advanced Micro Devices, Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file vktBindingDescriptorBufferTests.cpp
22  * \brief Descriptor buffer (extension) tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "deSharedPtr.hpp"
26 #include "deUniquePtr.hpp"
27 #include "deRandom.hpp"
28 #include "tcuCommandLine.hpp"
29 #include "vktBindingDescriptorBufferTests.hpp"
30 #include "vktTestCaseUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vktCustomInstancesDevices.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkObjUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkStrUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkImageUtil.hpp"
42 #include "vkRayTracingUtil.hpp"
43 
44 #include <algorithm>
45 
46 // The defines below can be changed for debugging purposes, otherwise keep them as is.
47 
48 #define DEBUG_FORCE_STAGED_UPLOAD false         // false - prefer direct write to device-local memory
49 #define DEBUG_MIX_DIRECT_AND_STAGED_UPLOAD true // true  - use some staged uploads to test new access flag
50 
51 // Workaround a framework script bug.
52 #ifndef VK_PIPELINE_STAGE_2_TRANSFER_BIT
53 #define VK_PIPELINE_STAGE_2_TRANSFER_BIT VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR
54 #endif
55 
56 namespace vkt
57 {
58 namespace BindingModel
59 {
60 namespace
61 {
62 using namespace vk;
63 using de::MovePtr;
64 using de::SharedPtr;
65 using de::UniquePtr;
66 
67 constexpr uint32_t INDEX_INVALID    = ~0u;
68 constexpr uint32_t OFFSET_UNUSED    = ~0u;
69 constexpr uint32_t HASH_MASK_FOR_AS = (1u << 19) - 1;
70 
71 constexpr uint32_t ConstResultBufferDwords     = 0x4;    // uvec4
72 constexpr uint32_t ConstInlineBlockDwords      = 0x40;   // 256 B spec minimum
73 constexpr uint32_t ConstUniformBufferDwords    = 0x1000; // 16 KiB spec minimum
74 constexpr uint32_t ConstTexelBufferElements    = 512;
75 constexpr uint32_t ConstMaxDescriptorArraySize = 3;   // at most define N-element descriptor arrays
76 constexpr uint32_t ConstRobustBufferAlignment  = 256; // 256 is the worst-case alignment required by UBOs in robustness2
77 constexpr uint32_t ConstChecksPerBuffer        = 4;   // when verifying data in buffers, do at most N comparisons;
78                                                       // this is to avoid excessive shader execution time
79 
80 constexpr VkComponentMapping ComponentMappingIdentity = {
81     VK_COMPONENT_SWIZZLE_IDENTITY,
82     VK_COMPONENT_SWIZZLE_IDENTITY,
83     VK_COMPONENT_SWIZZLE_IDENTITY,
84     VK_COMPONENT_SWIZZLE_IDENTITY,
85 };
86 
87 template <typename T>
u32(const T & value)88 inline uint32_t u32(const T &value)
89 {
90     return static_cast<uint32_t>(value);
91 }
92 
93 template <typename T, typename... args_t>
newMovePtr(args_t &&...args)94 inline de::MovePtr<T> newMovePtr(args_t &&...args)
95 {
96     return de::MovePtr<T>(new T(::std::forward<args_t>(args)...));
97 }
98 
99 template <typename T>
reset(Move<T> & ptr)100 inline void reset(Move<T> &ptr)
101 {
102     ptr = Move<T>();
103 }
104 
105 template <typename T>
reset(MovePtr<T> & ptr)106 inline void reset(MovePtr<T> &ptr)
107 {
108     ptr.clear();
109 }
110 
111 template <typename T>
makeSharedUniquePtr()112 inline SharedPtr<UniquePtr<T>> makeSharedUniquePtr()
113 {
114     return SharedPtr<UniquePtr<T>>(new UniquePtr<T>(new T()));
115 }
116 
offsetPtr(void * ptr,VkDeviceSize offset)117 inline void *offsetPtr(void *ptr, VkDeviceSize offset)
118 {
119     return reinterpret_cast<char *>(ptr) + offset;
120 }
121 
offsetPtr(const void * ptr,VkDeviceSize offset)122 inline const void *offsetPtr(const void *ptr, VkDeviceSize offset)
123 {
124     return reinterpret_cast<const char *>(ptr) + offset;
125 }
126 
127 // Calculate the byte offset of ptr from basePtr.
128 // This can be useful if an object at ptr is suballocated from a larger allocation at basePtr, for example.
basePtrOffsetOf(const void * basePtr,const void * ptr)129 inline std::size_t basePtrOffsetOf(const void *basePtr, const void *ptr)
130 {
131     DE_ASSERT(basePtr <= ptr);
132     return static_cast<std::size_t>(static_cast<const uint8_t *>(ptr) - static_cast<const uint8_t *>(basePtr));
133 }
134 
getShaderGroupHandleSize(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)135 uint32_t getShaderGroupHandleSize(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
136 {
137     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
138 
139     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
140 
141     return rayTracingPropertiesKHR->getShaderGroupHandleSize();
142 }
143 
getShaderGroupBaseAlignment(const InstanceInterface & vki,const VkPhysicalDevice physicalDevice)144 uint32_t getShaderGroupBaseAlignment(const InstanceInterface &vki, const VkPhysicalDevice physicalDevice)
145 {
146     de::MovePtr<RayTracingProperties> rayTracingPropertiesKHR;
147 
148     rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
149 
150     return rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
151 }
152 
getVkBuffer(const de::MovePtr<BufferWithMemory> & buffer)153 VkBuffer getVkBuffer(const de::MovePtr<BufferWithMemory> &buffer)
154 {
155     VkBuffer result = (buffer.get() == DE_NULL) ? DE_NULL : buffer->get();
156 
157     return result;
158 }
159 
makeStridedDeviceAddressRegion(const DeviceInterface & vkd,const VkDevice device,VkBuffer buffer,VkDeviceSize size)160 VkStridedDeviceAddressRegionKHR makeStridedDeviceAddressRegion(const DeviceInterface &vkd, const VkDevice device,
161                                                                VkBuffer buffer, VkDeviceSize size)
162 {
163     const VkDeviceSize sizeFixed = ((buffer == DE_NULL) ? 0ull : size);
164 
165     return makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, buffer, 0), sizeFixed, sizeFixed);
166 }
167 
getAccelerationStructureDeviceAddress(DeviceDriver & deviceDriver,VkDevice device,VkAccelerationStructureKHR accelerationStructure)168 VkDeviceAddress getAccelerationStructureDeviceAddress(DeviceDriver &deviceDriver, VkDevice device,
169                                                       VkAccelerationStructureKHR accelerationStructure)
170 {
171     const VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {
172         VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, // VkStructureType                sType
173         DE_NULL,                                                          // const void*                    pNext
174         accelerationStructure // VkAccelerationStructureKHR    accelerationStructure
175     };
176     const VkDeviceAddress deviceAddress = deviceDriver.getAccelerationStructureDeviceAddressKHR(device, &addressInfo);
177 
178     DE_ASSERT(deviceAddress != DE_NULL);
179 
180     return deviceAddress;
181 }
182 
183 // Used to distinguish different test implementations.
184 enum class TestVariant : uint32_t
185 {
186     SINGLE,                      // basic quick check for descriptor/shader combinations
187     MULTIPLE,                    // multiple buffer bindings with various descriptor types
188     MAX,                         // verify max(Sampler/Resource)DescriptorBufferBindings
189     EMBEDDED_IMMUTABLE_SAMPLERS, // various usages of embedded immutable samplers
190     PUSH_DESCRIPTOR,             // use push descriptors and descriptor buffer at the same time
191     PUSH_TEMPLATE,               // use push descriptor template and descriptor buffer at the same time
192     ROBUST_BUFFER_ACCESS,        // robust buffer access
193     ROBUST_NULL_DESCRIPTOR,      // robustness2 with null descriptor
194     CAPTURE_REPLAY,              // capture and replay capability with descriptor buffers
195     MUTABLE_DESCRIPTOR_TYPE,     // use VK_EXT_mutable_descriptor_type
196     YCBCR_SAMPLER,               // use VK_KHR_sampler_ycbcr_conversion
197 };
198 
199 // Optional; Used to add variations for a specific test case.
200 enum class SubCase : uint32_t
201 {
202     NONE,                               // no sub case, i.e. a baseline test case
203     IMMUTABLE_SAMPLERS,                 // treat all samplers as immutable
204     CAPTURE_REPLAY_CUSTOM_BORDER_COLOR, // in capture/replay tests, test VK_EXT_custom_border_color interaction
205     SINGLE_BUFFER,       // use push descriptors and descriptor buffer at the same time using single buffer
206     YCBCR_SAMPLER_ARRAY, // a more complex case with arrayed combined image samplers
207 };
208 
209 // A simplified descriptor binding, used to define the test case behavior at a high level.
210 struct SimpleBinding
211 {
212     uint32_t set;
213     uint32_t binding;
214     VkDescriptorType type;
215     uint32_t count;
216     uint32_t inputAttachmentIndex;
217 
218     bool isResultBuffer;             // binding used for compute buffer results
219     bool isEmbeddedImmutableSampler; // binding used as immutable embedded sampler
220     bool isRayTracingAS;             // binding used for raytracing acceleration structure
221 };
222 
223 // Scan simple bindings for the binding with the compute and ray tracing shader's result storage buffer.
getResultBufferIndex(const std::vector<SimpleBinding> & simpleBindings)224 uint32_t getResultBufferIndex(const std::vector<SimpleBinding> &simpleBindings)
225 {
226     bool found                 = false;
227     uint32_t resultBufferIndex = 0;
228 
229     for (const auto &sb : simpleBindings)
230     {
231         if (sb.isResultBuffer)
232         {
233             found = true;
234 
235             break;
236         }
237 
238         ++resultBufferIndex;
239     }
240 
241     if (!found)
242     {
243         resultBufferIndex = INDEX_INVALID;
244     }
245 
246     return resultBufferIndex;
247 }
248 
249 // Scan simple bindings for the binding with the ray tracing acceleration structure
getRayTracingASIndex(const std::vector<SimpleBinding> & simpleBindings)250 uint32_t getRayTracingASIndex(const std::vector<SimpleBinding> &simpleBindings)
251 {
252     uint32_t ndx    = 0;
253     uint32_t result = INDEX_INVALID;
254 
255     for (const auto &sb : simpleBindings)
256     {
257         if (sb.isRayTracingAS)
258         {
259             result = ndx;
260 
261             break;
262         }
263 
264         ++ndx;
265     }
266 
267     DE_ASSERT(result != INDEX_INVALID);
268 
269     return result;
270 }
271 
272 // A mask of descriptor types, with opaque mapping of VkDescriptorType to bits.
273 // Use the provided functions to get/set bits.
274 typedef uint32_t DescriptorMask;
275 
maskCheck(DescriptorMask mask,VkDescriptorType type)276 inline bool maskCheck(DescriptorMask mask, VkDescriptorType type)
277 {
278     DE_ASSERT(static_cast<uint32_t>(type) < 32);
279     return (mask & (1u << static_cast<uint32_t>(type))) != 0;
280 }
281 
maskSet(DescriptorMask * pMask,VkDescriptorType type)282 inline void maskSet(DescriptorMask *pMask, VkDescriptorType type)
283 {
284     DE_ASSERT(static_cast<uint32_t>(type) < 32);
285     *pMask |= (1u << static_cast<uint32_t>(type));
286 }
287 
makeDescriptorMask(const std::initializer_list<VkDescriptorType> & types)288 DescriptorMask makeDescriptorMask(const std::initializer_list<VkDescriptorType> &types)
289 {
290     DescriptorMask mask = 0u;
291     for (const auto &t : types)
292     {
293         maskSet(&mask, t);
294     }
295     return mask;
296 }
297 
getDescriptorMaskTypes(DescriptorMask inputMask)298 std::vector<VkDescriptorType> getDescriptorMaskTypes(DescriptorMask inputMask)
299 {
300     static const VkDescriptorType consideredTypes[]{
301         VK_DESCRIPTOR_TYPE_SAMPLER,
302         VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
303         VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
304         VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
305         VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
306         VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
307         VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
308         VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
309         VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
310     };
311 
312     std::vector<VkDescriptorType> types;
313 
314     for (const auto &type : consideredTypes)
315     {
316         uint32_t typeMask = 0u;
317         maskSet(&typeMask, type);
318 
319         if ((inputMask & typeMask) != 0)
320         {
321             types.emplace_back(type);
322             inputMask &= ~typeMask; // clear the bit corresponding to this descriptor type
323         }
324 
325         if (inputMask == 0)
326         {
327             // Early exit
328             break;
329         }
330     }
331 
332     // Ensure that all bits were accounted for
333     DE_ASSERT(inputMask == 0);
334 
335     return types;
336 }
337 
338 // The parameters for a test case (with the exclusion of simple bindings).
339 // Not all values are used by every test variant.
340 struct TestParams
341 {
342     uint32_t hash;               // a value used to "salt" results in memory to get unique values per test case
343     TestVariant variant;         // general type of the test case
344     SubCase subcase;             // a variation of the specific test case
345     VkShaderStageFlagBits stage; // which shader makes use of the bindings
346     VkQueueFlagBits queue;       // which queue to use for the access
347     uint32_t bufferBindingCount; // number of buffer bindings to create
348     uint32_t setsPerBuffer;      // how may sets to put in one buffer binding
349     bool useMaintenance5;        // should we use VkPipelineCreateFlagBits2KHR
350 
351     // Basic, null descriptor, capture/replay, or ycbcr sampler test
352     VkDescriptorType descriptor; // descriptor type under test
353 
354     // Max bindings test and to check the supported limits in other cases
355     uint32_t samplerBufferBindingCount;
356     uint32_t resourceBufferBindingCount;
357 
358     // Max embedded immutable samplers test
359     uint32_t embeddedImmutableSamplerBufferBindingCount;
360     uint32_t embeddedImmutableSamplersPerBuffer;
361 
362     // Push descriptors
363     uint32_t pushDescriptorSetIndex; // which descriptor set is updated with push descriptor/template
364 
365     // Mutable descriptor type
366     DescriptorMask mutableDescriptorTypes; // determines the descriptor types for VkMutableDescriptorTypeListEXT
367 
368     bool commands2; // Use vkCmd* commands from VK_KHR_maintenance6
369 
isComputevkt::BindingModel::__anonb91d530b0111::TestParams370     bool isCompute() const
371     {
372         return stage == VK_SHADER_STAGE_COMPUTE_BIT;
373     }
374 
isGraphicsvkt::BindingModel::__anonb91d530b0111::TestParams375     bool isGraphics() const
376     {
377         return (stage & VK_SHADER_STAGE_ALL_GRAPHICS) != 0;
378     }
379 
isGeometryvkt::BindingModel::__anonb91d530b0111::TestParams380     bool isGeometry() const
381     {
382         return stage == VK_SHADER_STAGE_GEOMETRY_BIT;
383     }
384 
isTessellationvkt::BindingModel::__anonb91d530b0111::TestParams385     bool isTessellation() const
386     {
387         return (stage & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) != 0;
388     }
389 
isPushDescriptorTestvkt::BindingModel::__anonb91d530b0111::TestParams390     bool isPushDescriptorTest() const
391     {
392         return (variant == TestVariant::PUSH_DESCRIPTOR) || (variant == TestVariant::PUSH_TEMPLATE);
393     }
394 
isAccelerationStructurevkt::BindingModel::__anonb91d530b0111::TestParams395     bool isAccelerationStructure() const
396     {
397         return descriptor == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
398     }
399 
isRayTracingvkt::BindingModel::__anonb91d530b0111::TestParams400     bool isRayTracing() const
401     {
402         return isAllRayTracingStages(stage);
403     }
404 
405     // The resource accessed via this descriptor type has capture/replay enabled.
isCaptureReplayDescriptorvkt::BindingModel::__anonb91d530b0111::TestParams406     bool isCaptureReplayDescriptor(VkDescriptorType otherType) const
407     {
408         return (variant == TestVariant::CAPTURE_REPLAY) && (descriptor == otherType);
409     }
410 
isAccelerationStructureOptionalvkt::BindingModel::__anonb91d530b0111::TestParams411     bool isAccelerationStructureOptional() const
412     {
413         switch (variant)
414         {
415         case TestVariant::MULTIPLE:
416         case TestVariant::PUSH_DESCRIPTOR:
417         case TestVariant::PUSH_TEMPLATE:
418         case TestVariant::MUTABLE_DESCRIPTOR_TYPE:
419             return true;
420         default:
421             return false;
422         }
423     }
424 
isAccelerationStructureObligatoryvkt::BindingModel::__anonb91d530b0111::TestParams425     bool isAccelerationStructureObligatory() const
426     {
427         switch (variant)
428         {
429         case TestVariant::SINGLE:
430         case TestVariant::ROBUST_NULL_DESCRIPTOR:
431         case TestVariant::CAPTURE_REPLAY:
432             return isAccelerationStructure();
433         default:
434             return false;
435         }
436     }
437 
438     // Update the hash field. Must be called after changing the value of any other parameters.
updateHashvkt::BindingModel::__anonb91d530b0111::TestParams439     void updateHash(uint32_t basehash)
440     {
441         hash = deUint32Hash(basehash);
442 
443         hash = isAccelerationStructure() ? (basehash & HASH_MASK_FOR_AS) : basehash;
444     }
445 };
446 
447 // A convenience holder for a buffer-related data.
448 struct BufferAlloc
449 {
450     VkDeviceSize size             = 0;
451     VkDeviceAddress deviceAddress = 0; // non-zero if used
452     VkBufferUsageFlags usage      = 0;
453     uint64_t opaqueCaptureAddress = 0;
454 
455     Move<VkBuffer> buffer;
456     MovePtr<Allocation> alloc;
457 
458     BufferAlloc()              = default;
459     BufferAlloc(BufferAlloc &) = delete;
460 
loadDeviceAddressvkt::BindingModel::__anonb91d530b0111::BufferAlloc461     void loadDeviceAddress(const DeviceInterface &vk, VkDevice device)
462     {
463         VkBufferDeviceAddressInfo bdaInfo = initVulkanStructure();
464         bdaInfo.buffer                    = *buffer;
465 
466         deviceAddress = vk.getBufferDeviceAddress(device, &bdaInfo);
467     }
468 };
469 
470 using BufferAllocPtr = SharedPtr<BufferAlloc>;
471 
472 // A convenience holder for image-related data.
473 struct ImageAlloc
474 {
475     VkImageCreateInfo info        = {};
476     VkDeviceSize sizeBytes        = 0;
477     VkImageLayout layout          = VK_IMAGE_LAYOUT_UNDEFINED; // layout used when image is accessed
478     uint64_t opaqueCaptureAddress = 0;
479 
480     Move<VkImage> image;
481     Move<VkImageView> imageView;
482     MovePtr<Allocation> alloc;
483 
484     ImageAlloc()             = default;
485     ImageAlloc(ImageAlloc &) = delete;
486 };
487 
488 using ImageAllocPtr = SharedPtr<ImageAlloc>;
489 
490 // A descriptor binding with supporting data.
491 class Binding
492 {
493 public:
494     uint32_t binding;
495     VkDescriptorType descriptorType; // always the actual descriptor type (i.e. even with mutable)
496     uint32_t descriptorCount;
497     VkShaderStageFlags stageFlags;
498 
499     VkDeviceSize offset;
500     uint32_t inputAttachmentIndex; // if used
501     bool isResultBuffer;           // used with compute shaders
502     bool isRayTracingAS;           // used with raytracing shaders
503     bool isMutableType;            // used with MUTABLE_DESCRIPTOR_TYPE cases
504 
isTestableDescriptor() const505     bool isTestableDescriptor() const
506     {
507         return !isRayTracingAS && !isResultBuffer;
508     }
509 
510     // Index into the vector of resources in the main test class, if used.
511     // It's an array, because a binding may have several arrayed descriptors.
512     uint32_t perBindingResourceIndex[ConstMaxDescriptorArraySize];
513 
514     // An array of immutable samplers, if used by the binding.
515     VkSampler immutableSamplers[ConstMaxDescriptorArraySize];
516 
Binding()517     Binding()
518         : binding(0)
519         , descriptorType(VK_DESCRIPTOR_TYPE_SAMPLER)
520         , descriptorCount(0)
521         , stageFlags(0)
522         , offset(0)
523         , inputAttachmentIndex(0)
524         , isResultBuffer(false)
525         , isRayTracingAS(false)
526         , isMutableType(false)
527     {
528         for (uint32_t i = 0; i < DE_LENGTH_OF_ARRAY(perBindingResourceIndex); ++i)
529         {
530             perBindingResourceIndex[i] = INDEX_INVALID;
531             immutableSamplers[i]       = 0;
532         }
533     }
534 };
535 
536 // Get an array of descriptor bindings, this is used in descriptor set layout creation.
getDescriptorSetLayoutBindings(const std::vector<Binding> & allBindings)537 std::vector<VkDescriptorSetLayoutBinding> getDescriptorSetLayoutBindings(const std::vector<Binding> &allBindings)
538 {
539     std::vector<VkDescriptorSetLayoutBinding> result;
540     result.reserve(allBindings.size());
541 
542     for (auto &binding : allBindings)
543     {
544         VkDescriptorSetLayoutBinding dslBinding{};
545         dslBinding.binding         = binding.binding;
546         dslBinding.descriptorType  = binding.descriptorType;
547         dslBinding.descriptorCount = binding.descriptorCount;
548         dslBinding.stageFlags      = binding.stageFlags;
549 
550         if (binding.immutableSamplers[0] != DE_NULL)
551         {
552             dslBinding.pImmutableSamplers = binding.immutableSamplers;
553         }
554 
555         if (binding.isMutableType)
556         {
557             dslBinding.descriptorType = VK_DESCRIPTOR_TYPE_MUTABLE_EXT;
558         }
559 
560         DE_ASSERT(dslBinding.descriptorCount != 0);
561         DE_ASSERT(dslBinding.stageFlags != 0);
562 
563         result.emplace_back(dslBinding);
564     }
565 
566     return result;
567 }
568 
569 // Descriptor data used with push descriptors (regular and templates).
570 struct PushDescriptorData
571 {
572     VkDescriptorImageInfo imageInfos[ConstMaxDescriptorArraySize];
573     VkDescriptorBufferInfo bufferInfos[ConstMaxDescriptorArraySize];
574     VkBufferView texelBufferViews[ConstMaxDescriptorArraySize];
575     VkAccelerationStructureKHR accelerationStructures[ConstMaxDescriptorArraySize];
576 };
577 
578 // A convenience holder for a descriptor set layout and its bindings.
579 struct DescriptorSetLayoutHolder
580 {
581     std::vector<Binding> bindings;
582 
583     Move<VkDescriptorSetLayout> layout;
584     VkDeviceSize sizeOfLayout         = 0;
585     uint32_t bufferIndex              = INDEX_INVALID;
586     VkDeviceSize bufferOffset         = 0;
587     VkDeviceSize stagingBufferOffset  = OFFSET_UNUSED;
588     bool hasEmbeddedImmutableSamplers = false;
589     bool usePushDescriptors           = false; // instead of descriptor buffer
590 
591     DescriptorSetLayoutHolder()                            = default;
592     DescriptorSetLayoutHolder(DescriptorSetLayoutHolder &) = delete;
593 };
594 
595 using DSLPtr = SharedPtr<UniquePtr<DescriptorSetLayoutHolder>>;
596 
597 // Get an array of descriptor set layouts.
getDescriptorSetLayouts(const std::vector<DSLPtr> & dslPtrs)598 std::vector<VkDescriptorSetLayout> getDescriptorSetLayouts(const std::vector<DSLPtr> &dslPtrs)
599 {
600     std::vector<VkDescriptorSetLayout> result;
601     result.reserve(dslPtrs.size());
602 
603     for (auto &pDsl : dslPtrs)
604     {
605         result.emplace_back((**pDsl).layout.get());
606     }
607 
608     return result;
609 }
610 
611 // A helper struct to keep descriptor's underlying resource data.
612 // This is intended to be flexible and support a mix of buffer/image/sampler, depending on the binding type.
613 struct ResourceHolder
614 {
615     BufferAlloc buffer;
616     ImageAlloc image;
617     Move<VkSampler> sampler;
618     Move<VkSamplerYcbcrConversion> samplerYcbcrConversion;
619     Move<VkBufferView> bufferView;
620     SharedPtr<BottomLevelAccelerationStructure> rtBlas;
621     MovePtr<TopLevelAccelerationStructure> rtTlas;
622 
623     struct
624     {
625         std::vector<uint8_t> bufferData;
626         std::vector<uint8_t> imageData;
627         std::vector<uint8_t> imageViewData;
628         std::vector<uint8_t> samplerData;
629         std::vector<uint8_t> accelerationStructureDataBlas;
630         std::vector<uint8_t> accelerationStructureDataTlas;
631     } captureReplay;
632 
633     ResourceHolder()                 = default;
634     ResourceHolder(ResourceHolder &) = delete;
635 };
636 
637 using ResourcePtr = SharedPtr<UniquePtr<ResourceHolder>>;
638 
639 // Used in test case name generation.
toString(VkQueueFlagBits queue)640 std::string toString(VkQueueFlagBits queue)
641 {
642     switch (queue)
643     {
644     case VK_QUEUE_GRAPHICS_BIT:
645         return "graphics";
646     case VK_QUEUE_COMPUTE_BIT:
647         return "compute";
648 
649     default:
650         DE_ASSERT(false);
651         break;
652     }
653     return "";
654 }
655 
656 // Used in test case name generation.
toString(VkDescriptorType type)657 std::string toString(VkDescriptorType type)
658 {
659     switch (type)
660     {
661     case VK_DESCRIPTOR_TYPE_SAMPLER:
662         return "sampler";
663     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
664         return "combined_image_sampler";
665     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
666         return "sampled_image";
667     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
668         return "storage_image";
669     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
670         return "uniform_texel_buffer";
671     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
672         return "storage_texel_buffer";
673     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
674         return "uniform_buffer";
675     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
676         return "storage_buffer";
677     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
678         return "input_attachment";
679     case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
680         return "inline_uniform_block";
681     case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
682         return "acceleration_structure";
683 
684     default:
685         DE_ASSERT(false);
686         break;
687     }
688     return "";
689 }
690 
691 // Used in test case name generation.
toString(VkShaderStageFlagBits stage)692 std::string toString(VkShaderStageFlagBits stage)
693 {
694     switch (stage)
695     {
696     case VK_SHADER_STAGE_VERTEX_BIT:
697         return "vert";
698     case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
699         return "tesc";
700     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
701         return "tese";
702     case VK_SHADER_STAGE_GEOMETRY_BIT:
703         return "geom";
704     case VK_SHADER_STAGE_FRAGMENT_BIT:
705         return "frag";
706     case VK_SHADER_STAGE_COMPUTE_BIT:
707         return "comp";
708     case VK_SHADER_STAGE_RAYGEN_BIT_KHR:
709         return "rgen";
710     case VK_SHADER_STAGE_ANY_HIT_BIT_KHR:
711         return "ahit";
712     case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
713         return "chit";
714     case VK_SHADER_STAGE_MISS_BIT_KHR:
715         return "miss";
716     case VK_SHADER_STAGE_INTERSECTION_BIT_KHR:
717         return "sect";
718     case VK_SHADER_STAGE_CALLABLE_BIT_KHR:
719         return "call";
720 
721     default:
722         DE_ASSERT(false);
723         break;
724     }
725 
726     return "";
727 }
728 
729 // Used in test case name generation.
getCaseNameUpdateHash(TestParams & params,uint32_t baseHash)730 std::string getCaseNameUpdateHash(TestParams &params, uint32_t baseHash)
731 {
732     std::ostringstream str;
733 
734     str << toString(params.queue) << "_" << toString(params.stage);
735 
736     if ((params.variant == TestVariant::SINGLE) || (params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) ||
737         (params.variant == TestVariant::CAPTURE_REPLAY))
738     {
739         str << "_" << toString(params.descriptor);
740 
741         if (params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
742         {
743             str << "_custom_border_color";
744         }
745     }
746     else if (params.variant == TestVariant::MULTIPLE)
747     {
748         str << "_buffers" << params.bufferBindingCount << "_sets" << params.setsPerBuffer;
749     }
750     else if (params.variant == TestVariant::MAX)
751     {
752         str << "_sampler" << params.samplerBufferBindingCount << "_resource" << params.resourceBufferBindingCount;
753     }
754     else if (params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
755     {
756         str << "_buffers" << params.embeddedImmutableSamplerBufferBindingCount << "_samplers"
757             << params.embeddedImmutableSamplersPerBuffer;
758     }
759     else if (params.isPushDescriptorTest())
760     {
761         str << "_sets" << (params.bufferBindingCount + 1) << "_push_set" << params.pushDescriptorSetIndex
762             << ((params.subcase == SubCase::SINGLE_BUFFER) ? "_single_buffer" : "");
763     }
764     else if (params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
765     {
766         str << "_type_mask" << params.mutableDescriptorTypes;
767     }
768 
769     if (params.subcase == SubCase::IMMUTABLE_SAMPLERS)
770     {
771         str << "_imm_samplers";
772     }
773     else if (params.subcase == SubCase::YCBCR_SAMPLER_ARRAY)
774     {
775         str << "_array";
776     }
777 
778     if (params.commands2)
779     {
780         str << "_commands_2";
781     }
782 
783     params.updateHash(baseHash ^ deStringHash(str.str().c_str()));
784 
785     return str.str();
786 }
787 
788 // Used by shaders to identify a specific binding.
packBindingArgs(uint32_t set,uint32_t binding,uint32_t arrayIndex)789 uint32_t packBindingArgs(uint32_t set, uint32_t binding, uint32_t arrayIndex)
790 {
791     DE_ASSERT(set < 0x40);
792     DE_ASSERT(binding < 0x40);
793     DE_ASSERT(arrayIndex < 0x80);
794 
795     return (arrayIndex << 12) | ((set & 0x3Fu) << 6) | (binding & 0x3Fu);
796 }
797 
798 // Used by shaders to identify a specific binding.
unpackBindingArgs(uint32_t packed,uint32_t * pOutSet,uint32_t * pBinding,uint32_t * pArrayIndex)799 void unpackBindingArgs(uint32_t packed, uint32_t *pOutSet, uint32_t *pBinding, uint32_t *pArrayIndex)
800 {
801     if (pBinding != nullptr)
802     {
803         *pBinding = packed & 0x3Fu;
804     }
805     if (pOutSet != nullptr)
806     {
807         *pOutSet = (packed >> 6) & 0x3Fu;
808     }
809     if (pArrayIndex != nullptr)
810     {
811         *pArrayIndex = (packed >> 12) & 0x7Fu;
812     }
813 }
814 
815 // The expected data read through a descriptor. Try to get a unique value per test and binding.
getExpectedData(uint32_t hash,uint32_t set,uint32_t binding,uint32_t arrayIndex=0)816 uint32_t getExpectedData(uint32_t hash, uint32_t set, uint32_t binding, uint32_t arrayIndex = 0)
817 {
818     return hash ^ packBindingArgs(set, binding, arrayIndex);
819 }
820 
821 // The returned vector contains G8 in x and B8R8 in y components (as defined by VK_FORMAT_G8_B8R8_2PLANE_420_UNORM).
getExpectedData_G8_B8R8(uint32_t hash,uint32_t set,uint32_t binding,uint32_t arrayIndex=0)822 tcu::UVec2 getExpectedData_G8_B8R8(uint32_t hash, uint32_t set, uint32_t binding, uint32_t arrayIndex = 0)
823 {
824     // Hash the input data to achieve "randomness" of components.
825     const uint32_t data = deUint32Hash(getExpectedData(hash, set, binding, arrayIndex));
826 
827     return tcu::UVec2((data >> 16) & 0xff, data & 0xffff);
828 }
829 
830 // Convert G8_B8R8_UNORM to float components.
toVec4_G8_B8R8(const tcu::UVec2 & input)831 tcu::Vec4 toVec4_G8_B8R8(const tcu::UVec2 &input)
832 {
833     return tcu::Vec4(float(((input.y() >> 8) & 0xff)) / 255.0f, float(input.x()) / 255.0f,
834                      float((input.y() & 0xff)) / 255.0f, 1.0f);
835 }
836 
837 // Used by shaders.
glslFormat(uint32_t value)838 std::string glslFormat(uint32_t value)
839 {
840     return std::to_string(value) + "u";
841 }
842 
843 // Generate a unique shader resource name for a binding.
glslResourceName(uint32_t set,uint32_t binding)844 std::string glslResourceName(uint32_t set, uint32_t binding)
845 {
846     // A generic name for any accessible shader binding.
847     std::ostringstream str;
848     str << "res_" << set << "_" << binding;
849     return str.str();
850 }
851 
852 // Generate GLSL that declares a descriptor binding.
glslDeclareBinding(VkDescriptorType type,uint32_t set,uint32_t binding,uint32_t count,uint32_t attachmentIndex,uint32_t bufferArraySize,VkFormat format)853 std::string glslDeclareBinding(VkDescriptorType type, uint32_t set, uint32_t binding, uint32_t count,
854                                uint32_t attachmentIndex, uint32_t bufferArraySize,
855                                VkFormat format) // for resources that use it
856 {
857     std::ostringstream str;
858 
859     str << "layout(set = " << set << ", binding = " << binding;
860 
861     std::string imagePrefix;
862     std::string imageFormat;
863 
864     if (format == VK_FORMAT_R32_UINT)
865     {
866         imagePrefix = "u";
867         imageFormat = "r32ui";
868     }
869     else if (format == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
870     {
871         imagePrefix = "";
872         imageFormat = "rgba8";
873     }
874     else
875     {
876         DE_ASSERT(0);
877     }
878 
879     // Additional layout information
880     switch (type)
881     {
882     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
883     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
884         str << ", " << imageFormat << ") ";
885         break;
886     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
887         str << ", input_attachment_index = " << attachmentIndex << ") ";
888         break;
889     default:
890         str << ") ";
891         break;
892     }
893 
894     switch (type)
895     {
896     case VK_DESCRIPTOR_TYPE_SAMPLER:
897         str << "uniform sampler ";
898         break;
899     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
900         str << "uniform " << imagePrefix << "sampler2D ";
901         break;
902     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
903         str << "uniform " << imagePrefix << "texture2D ";
904         break;
905     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
906         str << "uniform " << imagePrefix << "image2D ";
907         break;
908     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
909         str << "uniform " << imagePrefix << "textureBuffer ";
910         break;
911     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
912         str << "uniform " << imagePrefix << "imageBuffer ";
913         break;
914     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
915     case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
916         DE_ASSERT(bufferArraySize != 0);
917         DE_ASSERT((bufferArraySize % 4) == 0);
918         // std140 layout rules, each array element is aligned to 16 bytes.
919         // Due to this, we will use uvec4 instead to access all dwords.
920         str << "uniform Buffer_" << set << "_" << binding << " {\n"
921             << "    uvec4 data[" << (bufferArraySize / 4) << "];\n"
922             << "} ";
923         break;
924     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
925         DE_ASSERT(bufferArraySize != 0);
926         str << "buffer Buffer_" << set << "_" << binding << " {\n"
927             << "    uint data[" << bufferArraySize << "];\n"
928             << "} ";
929         break;
930     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
931         str << "uniform " << imagePrefix << "subpassInput ";
932         break;
933     case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
934         str << "uniform accelerationStructureEXT ";
935         break;
936     default:
937         DE_ASSERT(0);
938         break;
939     }
940 
941     str << glslResourceName(set, binding);
942 
943     if (count > 1)
944     {
945         str << "[" << count << "];\n";
946     }
947     else
948     {
949         str << ";\n";
950     }
951 
952     return str.str();
953 }
954 
955 // Generate all GLSL descriptor set/binding declarations.
glslGlobalDeclarations(const TestParams & params,const std::vector<SimpleBinding> & simpleBindings,bool accStruct)956 std::string glslGlobalDeclarations(const TestParams &params, const std::vector<SimpleBinding> &simpleBindings,
957                                    bool accStruct)
958 {
959     DE_UNREF(params);
960 
961     std::ostringstream str;
962 
963     if (accStruct)
964         str << "#extension GL_EXT_ray_query : require\n";
965 
966     for (const auto &sb : simpleBindings)
967     {
968         const uint32_t arraySize = sb.isResultBuffer                                    ? ConstResultBufferDwords :
969                                    (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ? ConstInlineBlockDwords :
970                                                                                           ConstUniformBufferDwords;
971 
972         VkFormat format;
973         if ((params.variant == TestVariant::YCBCR_SAMPLER) && (sb.type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
974         {
975             format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
976         }
977         else
978         {
979             format = VK_FORMAT_R32_UINT;
980         }
981 
982         str << glslDeclareBinding(sb.type, sb.set, sb.binding, sb.count, sb.inputAttachmentIndex, arraySize, format);
983     }
984 
985     if (accStruct)
986     {
987         str << ""
988                "uint queryAS(accelerationStructureEXT rayQueryTopLevelAccelerationStructure)\n"
989                "{\n"
990                "    const uint  rayFlags = gl_RayFlagsNoOpaqueEXT;\n"
991                "    const uint  cullMask = 0xFF;\n"
992                "    const float tmin     = 0.0f;\n"
993                "    const float tmax     = 524288.0f; // 2^^19\n"
994                "    const vec3  origin   = vec3(0.0f, 0.0f, 0.0f);\n"
995                "    const vec3  direct   = vec3(0.0f, 0.0f, 1.0f);\n"
996                "    rayQueryEXT rayQuery;\n"
997                "\n"
998                "    rayQueryInitializeEXT(rayQuery, rayQueryTopLevelAccelerationStructure, rayFlags, cullMask, origin, "
999                "tmin, direct, tmax);\n"
1000                "\n"
1001                "    if (rayQueryProceedEXT(rayQuery))\n"
1002                "    {\n"
1003                "        if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == "
1004                "gl_RayQueryCandidateIntersectionTriangleEXT)\n"
1005                "        {\n"
1006                "            return uint(round(rayQueryGetIntersectionTEXT(rayQuery, false)));\n"
1007                "        }\n"
1008                "    }\n"
1009                "\n"
1010                "    return 0u;\n"
1011                "}\n"
1012                "\n";
1013     }
1014 
1015     return str.str();
1016 }
1017 
1018 // This function is used to return additional diagnostic information for a failed descriptor binding.
1019 // For example, result Y is the packed binding information and result Z is the array index (for arrayed descriptors, or buffers).
glslResultBlock(const std::string & indent,const std::string & resultY,const std::string & resultZ="")1020 std::string glslResultBlock(const std::string &indent, const std::string &resultY, const std::string &resultZ = "")
1021 {
1022     std::ostringstream str;
1023     str << "{\n"
1024         << indent << "    result.x += 1;\n"
1025         << indent << "} else if (result.y == 0) {\n"
1026         << indent << "    result.y = " << resultY << ";\n";
1027 
1028     if (!resultZ.empty())
1029     {
1030         str << indent << "    result.z = " << resultZ << ";\n";
1031     }
1032 
1033     str << indent << "}\n";
1034     return str.str();
1035 }
1036 
1037 // Get the number of iterations required to access all elements of a buffer.
1038 // This mainly exists because we access UBOs as uvec4.
getBufferLoopIterations(VkDescriptorType type)1039 inline uint32_t getBufferLoopIterations(VkDescriptorType type)
1040 {
1041     switch (type)
1042     {
1043     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1044         return ConstUniformBufferDwords / 4;
1045 
1046     case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
1047         return ConstInlineBlockDwords / 4;
1048 
1049     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1050         return ConstUniformBufferDwords;
1051 
1052     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1053     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1054         return ConstTexelBufferElements;
1055 
1056     default:
1057         // Ignored
1058         return 0;
1059     }
1060 }
1061 
1062 // Generate GLSL that reads through the binding and compares the value.
1063 // Successful reads increment a counter, while failed read will write back debug information.
glslOutputVerification(const TestParams & params,const std::vector<SimpleBinding> & simpleBindings,bool)1064 std::string glslOutputVerification(const TestParams &params, const std::vector<SimpleBinding> &simpleBindings, bool)
1065 {
1066     std::ostringstream str;
1067 
1068     if ((params.variant == TestVariant::SINGLE) || (params.variant == TestVariant::MULTIPLE) ||
1069         (params.variant == TestVariant::PUSH_DESCRIPTOR) || (params.variant == TestVariant::PUSH_TEMPLATE) ||
1070         (params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) ||
1071         (params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE) || (params.variant == TestVariant::CAPTURE_REPLAY) ||
1072         (params.variant == TestVariant::YCBCR_SAMPLER))
1073     {
1074         // Read at least one value from a descriptor and compare it.
1075         // For buffers, verify every element.
1076         //
1077         // With null descriptors, reads must always return zero.
1078 
1079         for (const auto &sb : simpleBindings)
1080         {
1081             uint32_t samplerIndex = INDEX_INVALID;
1082 
1083             if (sb.isResultBuffer || sb.isRayTracingAS)
1084             {
1085                 // Used by other bindings.
1086                 continue;
1087             }
1088 
1089             if (sb.type == VK_DESCRIPTOR_TYPE_SAMPLER)
1090             {
1091                 // Used by sampled images.
1092                 continue;
1093             }
1094             else if (sb.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
1095             {
1096                 // Sampled images require a sampler to use.
1097                 // Find a suitable sampler within the same descriptor set.
1098 
1099                 bool found   = false;
1100                 samplerIndex = 0;
1101 
1102                 for (const auto &sb1 : simpleBindings)
1103                 {
1104                     if ((sb.set == sb1.set) && (sb1.type == VK_DESCRIPTOR_TYPE_SAMPLER))
1105                     {
1106                         found = true;
1107                         break;
1108                     }
1109 
1110                     ++samplerIndex;
1111                 }
1112 
1113                 if (!found)
1114                 {
1115                     samplerIndex = INDEX_INVALID;
1116                 }
1117             }
1118 
1119             const uint32_t bufferLoopIterations = getBufferLoopIterations(sb.type);
1120             const uint32_t loopIncrement        = bufferLoopIterations / (ConstChecksPerBuffer - 1);
1121 
1122             // Ensure we won't miss the last check (the index will always be less than the buffer length).
1123             DE_ASSERT((bufferLoopIterations == 0) || ((bufferLoopIterations % (ConstChecksPerBuffer - 1)) != 0));
1124 
1125             const bool isNullDescriptor =
1126                 (params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) && (sb.type == params.descriptor);
1127             const bool isCustomBorderColor = (params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR);
1128 
1129             for (uint32_t arrayIndex = 0; arrayIndex < sb.count; ++arrayIndex)
1130             {
1131                 // Input attachment index increases with array index.
1132                 const auto expectedData =
1133                     glslFormat(isNullDescriptor ? 0 :
1134                                                   getExpectedData(params.hash, sb.set, sb.binding,
1135                                                                   sb.inputAttachmentIndex + arrayIndex));
1136                 const auto expectedBorderColor = isNullDescriptor    ? "uvec4(0)" :
1137                                                  isCustomBorderColor ? "uvec4(2, 0, 0, 1)" :
1138                                                                        "uvec4(0, 0, 0, 1)";
1139                 const auto bindingArgs =
1140                     glslFormat(packBindingArgs(sb.set, sb.binding, sb.inputAttachmentIndex + arrayIndex));
1141                 const auto &subscript = (sb.count > 1) ? "[" + std::to_string(arrayIndex) + "]" : "";
1142 
1143                 if (sb.type == VK_DESCRIPTOR_TYPE_SAMPLER)
1144                 {
1145                     TCU_THROW(InternalError, "Sampler is tested implicitly");
1146                 }
1147                 else if (sb.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
1148                 {
1149                     str << "    if (queryAS(" << glslResourceName(sb.set, sb.binding) << subscript
1150                         << ") == " << expectedData << ") " << glslResultBlock("\t", bindingArgs);
1151                 }
1152                 else if (sb.type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
1153                 {
1154                     str << "    if (subpassLoad(" << glslResourceName(sb.set, sb.binding) << subscript
1155                         << ").r == " << expectedData << ") " << glslResultBlock("\t", bindingArgs);
1156                 }
1157                 else if (sb.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
1158                 {
1159                     DE_ASSERT(samplerIndex != INDEX_INVALID);
1160                     const auto &samplerSb = simpleBindings[samplerIndex];
1161                     const auto &samplerSubscript =
1162                         (samplerSb.count > 1) ? "[" + std::to_string(arrayIndex % samplerSb.count) + "]" : "";
1163 
1164                     // With samplers, verify the image color and the border color.
1165 
1166                     std::stringstream samplerStr;
1167                     samplerStr << "usampler2D(" << glslResourceName(sb.set, sb.binding) << subscript << ", "
1168                                << glslResourceName(samplerSb.set, samplerSb.binding) << samplerSubscript << ")";
1169 
1170                     str << "    if ((textureLod(" << samplerStr.str() << ", vec2(0, 0), 0).r == " << expectedData
1171                         << ") &&\n"
1172                         << "        (textureLod(" << samplerStr.str() << ", vec2(-1, 0), 0) == " << expectedBorderColor
1173                         << ")) " << glslResultBlock("\t", bindingArgs);
1174                 }
1175                 else if (sb.type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1176                 {
1177                     if (params.variant == TestVariant::YCBCR_SAMPLER)
1178                     {
1179                         const auto ycbcrData         = getExpectedData_G8_B8R8(params.hash, sb.set, sb.binding,
1180                                                                                sb.inputAttachmentIndex + arrayIndex);
1181                         const auto expectedDataFloat = toVec4_G8_B8R8(ycbcrData);
1182 
1183                         // No border color with ycbcr samplers. 0.005 tolerance is a bit more than 1/255.
1184                         str << "\t{\n"
1185                             << "    vec4 color = textureLod(" << glslResourceName(sb.set, sb.binding) << subscript
1186                             << ", vec2(0, 0), 0);\n"
1187                             << "    if ((abs(" << expectedDataFloat.x() << " - color.r) < 0.005) &&\n"
1188                             << "        (abs(" << expectedDataFloat.y() << " - color.g) < 0.005) &&\n"
1189                             << "        (abs(" << expectedDataFloat.z() << " - color.b) < 0.005) &&\n"
1190                             << "        (color.a == 1.0)) " << glslResultBlock("\t\t", bindingArgs) << "\t}\n";
1191                     }
1192                     else
1193                     {
1194                         str << "    if ((textureLod(" << glslResourceName(sb.set, sb.binding) << subscript
1195                             << ", vec2(0, 0), 0).r == " << expectedData << ") &&\n"
1196                             << "        (textureLod(" << glslResourceName(sb.set, sb.binding) << subscript
1197                             << ", vec2(-1, 0), 0) == " << expectedBorderColor << ")) "
1198                             << glslResultBlock("\t", bindingArgs);
1199                     }
1200                 }
1201                 else if (sb.type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1202                 {
1203                     str << "    if (imageLoad(" << glslResourceName(sb.set, sb.binding) << subscript
1204                         << ", ivec2(0, 0)).r == " << expectedData << ") " << glslResultBlock("\t", bindingArgs);
1205                 }
1206                 else if ((sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
1207                          (sb.type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
1208                 {
1209                     const auto loadOp =
1210                         (sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ? "texelFetch" : "imageLoad";
1211                     const auto loopData = isNullDescriptor ? expectedData : "(" + expectedData + " + i)";
1212 
1213                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1214                         << "; i += " << glslFormat(loopIncrement) << ") {\n"
1215                         << "        uint value = " << loadOp << "(" << glslResourceName(sb.set, sb.binding) << subscript
1216                         << ", int(i)).r;\n"
1217                         << "        if (value == " << loopData << ") " << glslResultBlock("\t\t", bindingArgs, "i")
1218                         << "    }\n";
1219                 }
1220                 else if ((sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
1221                          (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK))
1222                 {
1223                     const auto loopData0 = isNullDescriptor ? expectedData : "(" + expectedData + " + 4 * i + 0)";
1224                     const auto loopData1 = isNullDescriptor ? expectedData : "(" + expectedData + " + 4 * i + 1)";
1225                     const auto loopData2 = isNullDescriptor ? expectedData : "(" + expectedData + " + 4 * i + 2)";
1226                     const auto loopData3 = isNullDescriptor ? expectedData : "(" + expectedData + " + 4 * i + 3)";
1227 
1228                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1229                         << "; i += " << glslFormat(loopIncrement) << ") {\n"
1230                         << "        uvec4 value = " << glslResourceName(sb.set, sb.binding) << subscript
1231                         << ".data[i];\n"
1232                         << "        if (value.x == " << loopData0 << ") "
1233                         << glslResultBlock("\t\t", bindingArgs, "4 * i + 0") << "        if (value.y == " << loopData1
1234                         << ") " << glslResultBlock("\t\t", bindingArgs, "4 * i + 1")
1235                         << "        if (value.z == " << loopData2 << ") "
1236                         << glslResultBlock("\t\t", bindingArgs, "4 * i + 2") << "        if (value.w == " << loopData3
1237                         << ") " << glslResultBlock("\t\t", bindingArgs, "4 * i + 3") << "    }\n";
1238                 }
1239                 else if (sb.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1240                 {
1241                     const auto loopData = isNullDescriptor ? expectedData : "(" + expectedData + " + i)";
1242 
1243                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1244                         << "; i += " << glslFormat(loopIncrement) << ") {\n"
1245                         << "        uint value = " << glslResourceName(sb.set, sb.binding) << subscript << ".data[i];\n"
1246                         << "        if (value == " << loopData << ") " << glslResultBlock("\t\t", bindingArgs, "i")
1247                         << "    }\n";
1248                 }
1249                 else
1250                 {
1251                     DE_ASSERT(0);
1252                 }
1253             }
1254         }
1255     }
1256     else if (params.variant == TestVariant::ROBUST_BUFFER_ACCESS)
1257     {
1258         // With robust buffer tests, the buffer is always filled with zeros and we read with an offset that will
1259         // eventually cause us to read past the end of the buffer.
1260 
1261         for (const auto &sb : simpleBindings)
1262         {
1263             if (sb.isResultBuffer || sb.isRayTracingAS)
1264             {
1265                 // Used by other bindings.
1266                 continue;
1267             }
1268 
1269             const uint32_t bufferLoopIterations = getBufferLoopIterations(sb.type);
1270             const uint32_t loopIncrement        = bufferLoopIterations / (ConstChecksPerBuffer - 1);
1271             const auto iterationOffsetStr       = glslFormat(bufferLoopIterations / 2);
1272 
1273             // Ensure we won't miss the last check (the index will always be less than the buffer length).
1274             DE_ASSERT((bufferLoopIterations == 0) || ((bufferLoopIterations % (ConstChecksPerBuffer - 1)) != 0));
1275 
1276             for (uint32_t arrayIndex = 0; arrayIndex < sb.count; ++arrayIndex)
1277             {
1278                 const auto bindingArgs =
1279                     glslFormat(packBindingArgs(sb.set, sb.binding, sb.inputAttachmentIndex + arrayIndex));
1280                 const auto &subscript = (sb.count > 1) ? "[" + std::to_string(arrayIndex) + "]" : "";
1281 
1282                 switch (sb.type)
1283                 {
1284                 case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1285                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1286                         << ";  i += " << glslFormat(loopIncrement) << ") {\n"
1287                         << "        if (texelFetch(" << glslResourceName(sb.set, sb.binding) << subscript
1288                         << ", int(i + " << iterationOffsetStr << ")).r == 0) "
1289                         << glslResultBlock("\t\t", bindingArgs, "i + " + iterationOffsetStr) << "    }\n";
1290                     break;
1291 
1292                 case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1293                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1294                         << ";  i += " << glslFormat(loopIncrement) << ") {\n"
1295                         << "        if (imageLoad(" << glslResourceName(sb.set, sb.binding) << subscript << ", int(i + "
1296                         << iterationOffsetStr << ")).r == 0) "
1297                         << glslResultBlock("\t\t", bindingArgs, "i + " + iterationOffsetStr) << "    }\n";
1298                     break;
1299 
1300                 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1301                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1302                         << ";  i += " << glslFormat(loopIncrement) << ") {\n"
1303                         << "        if (" << glslResourceName(sb.set, sb.binding) << subscript << ".data[i + "
1304                         << iterationOffsetStr << "].x == 0) "
1305                         << glslResultBlock("\t\t", bindingArgs, "4 * i + " + iterationOffsetStr + " + 0")
1306                         << "        if (" << glslResourceName(sb.set, sb.binding) << subscript << ".data[i + "
1307                         << iterationOffsetStr << "].y == 0) "
1308                         << glslResultBlock("\t\t", bindingArgs, "4 * i + " + iterationOffsetStr + " + 1")
1309                         << "        if (" << glslResourceName(sb.set, sb.binding) << subscript << ".data[i + "
1310                         << iterationOffsetStr << "].z == 0) "
1311                         << glslResultBlock("\t\t", bindingArgs, "4 * i + " + iterationOffsetStr + " + 2")
1312                         << "        if (" << glslResourceName(sb.set, sb.binding) << subscript << ".data[i + "
1313                         << iterationOffsetStr << "].w == 0) "
1314                         << glslResultBlock("\t\t", bindingArgs, "4 * i + " + iterationOffsetStr + " + 3") << "    }\n";
1315                     break;
1316 
1317                 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1318                     str << "    for (uint i = 0; i < " << glslFormat(bufferLoopIterations)
1319                         << ";  i += " << glslFormat(loopIncrement) << ") {\n"
1320                         << "        if (" << glslResourceName(sb.set, sb.binding) << subscript << ".data[i + "
1321                         << iterationOffsetStr << "] == 0) "
1322                         << glslResultBlock("\t\t", bindingArgs, "i + " + iterationOffsetStr) << "    }\n";
1323                     break;
1324 
1325                 default:
1326                     DE_ASSERT(0);
1327                     break;
1328                 }
1329             }
1330         }
1331     }
1332     else if (params.variant == TestVariant::MAX)
1333     {
1334         std::vector<uint32_t> samplerIndices;
1335         std::vector<uint32_t> imageIndices;
1336 
1337         for (uint32_t i = 0; i < u32(simpleBindings.size()); ++i)
1338         {
1339             const auto &binding = simpleBindings[i];
1340 
1341             if (binding.type == VK_DESCRIPTOR_TYPE_SAMPLER)
1342             {
1343                 samplerIndices.emplace_back(i);
1344             }
1345             else if (binding.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
1346             {
1347                 imageIndices.emplace_back(i);
1348             }
1349             // Ignore other descriptors, if any.
1350         }
1351 
1352         // Ensure that all samplers and images are accessed at least once. If we run out of one, simply reuse it.
1353 
1354         const auto maxIndex = deMaxu32(u32(samplerIndices.size()), u32(imageIndices.size()));
1355 
1356         for (uint32_t index = 0; index < maxIndex; ++index)
1357         {
1358             const auto &samplerBinding = simpleBindings[samplerIndices[index % samplerIndices.size()]];
1359             const auto &imageBinding   = simpleBindings[imageIndices[index % imageIndices.size()]];
1360 
1361             const auto expectedData =
1362                 glslFormat(getExpectedData(params.hash, imageBinding.set, imageBinding.binding, 0));
1363             const auto imageBindingArgs   = glslFormat(packBindingArgs(imageBinding.set, imageBinding.binding, 0));
1364             const auto samplerBindingArgs = glslFormat(packBindingArgs(samplerBinding.set, samplerBinding.binding, 0));
1365 
1366             std::stringstream samplerStr;
1367             samplerStr << "usampler2D(" << glslResourceName(imageBinding.set, imageBinding.binding) << ", "
1368                        << glslResourceName(samplerBinding.set, samplerBinding.binding) << ")";
1369 
1370             str << "    if ((textureLod(" << samplerStr.str() << ", vec2(0, 0), 0).r == " << expectedData << ") &&\n"
1371                 << "        (textureLod(" << samplerStr.str() << ", vec2(-1, 0), 0) == uvec4(0, 0, 0, 1))) "
1372                 << glslResultBlock("\t", imageBindingArgs, samplerBindingArgs);
1373         }
1374     }
1375     else if (params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
1376     {
1377         // The first few sets contain only samplers.
1378         // Then the last set contains only images.
1379         // Optionally, the last binding of that set is the compute result buffer.
1380 
1381         uint32_t firstImageIndex = 0;
1382         uint32_t lastImageIndex  = 0;
1383 
1384         for (uint32_t i = 0; i < u32(simpleBindings.size()); ++i)
1385         {
1386             const auto &binding = simpleBindings[i];
1387 
1388             if (binding.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
1389             {
1390                 if (firstImageIndex == 0)
1391                 {
1392                     firstImageIndex = i;
1393                 }
1394 
1395                 lastImageIndex = i;
1396             }
1397         }
1398 
1399         DE_ASSERT(firstImageIndex == (lastImageIndex + 1 - firstImageIndex)); // same number of images and samplers
1400 
1401         for (uint32_t imageIndex = firstImageIndex; imageIndex <= lastImageIndex; ++imageIndex)
1402         {
1403             const auto &imageBinding = simpleBindings[imageIndex];
1404             const auto expectedData =
1405                 glslFormat(getExpectedData(params.hash, imageBinding.set, imageBinding.binding, 0));
1406             const auto bindingArgs = glslFormat(packBindingArgs(imageBinding.set, imageBinding.binding, 0));
1407 
1408             DE_ASSERT(imageBinding.type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
1409 
1410             const auto &samplerBinding    = simpleBindings[imageIndex - firstImageIndex];
1411             const auto samplerBindingArgs = glslFormat(packBindingArgs(samplerBinding.set, samplerBinding.binding, 0));
1412 
1413             std::stringstream samplerStr;
1414             samplerStr << "usampler2D(" << glslResourceName(imageBinding.set, imageBinding.binding) << ", "
1415                        << glslResourceName(samplerBinding.set, samplerBinding.binding) << ")";
1416 
1417             str << "    if ((textureLod(" << samplerStr.str() << ", vec2(0, 0), 0).r == " << expectedData << ") &&\n"
1418                 << "        (textureLod(" << samplerStr.str() << ", vec2(-1, 0), 0) == uvec4(0, 0, 0, 1))) "
1419                 << glslResultBlock("\t", bindingArgs, samplerBindingArgs);
1420         }
1421     }
1422     else
1423     {
1424         TCU_THROW(InternalError, "Not implemented");
1425     }
1426 
1427     // Compute shaders write the result to a storage buffer.
1428     const uint32_t computeResultBufferIndex = getResultBufferIndex(simpleBindings);
1429 
1430     if (computeResultBufferIndex != INDEX_INVALID)
1431     {
1432         DE_ASSERT(params.isCompute() || params.isRayTracing());
1433         const auto &resultSb = simpleBindings[computeResultBufferIndex];
1434 
1435         str << "    " << glslResourceName(resultSb.set, resultSb.binding) << ".data[0] = result.x;\n";
1436         str << "    " << glslResourceName(resultSb.set, resultSb.binding) << ".data[1] = result.y;\n";
1437         str << "    " << glslResourceName(resultSb.set, resultSb.binding) << ".data[2] = result.z;\n";
1438         str << "    " << glslResourceName(resultSb.set, resultSb.binding) << ".data[3] = result.w;\n";
1439     }
1440 
1441     return str.str();
1442 }
1443 
1444 // Base class for all test cases.
1445 class DescriptorBufferTestCase : public TestCase
1446 {
1447 public:
DescriptorBufferTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)1448     DescriptorBufferTestCase(tcu::TestContext &testCtx, const std::string &name, const TestParams &params)
1449 
1450         : TestCase(testCtx, name)
1451         , m_params(params)
1452         , m_rng(params.hash)
1453     {
1454     }
1455 
1456     void delayedInit();
1457     void initPrograms(vk::SourceCollections &programCollection) const;
1458     void initPrograms(vk::SourceCollections &programCollection, const std::vector<SimpleBinding> &simpleBinding,
1459                       bool accStruct, bool addService) const;
1460     TestInstance *createInstance(Context &context) const;
1461     void checkSupport(Context &context) const;
1462 
1463 private:
1464     const TestParams m_params;
1465     de::Random m_rng;
1466     std::vector<SimpleBinding> m_simpleBindings;
1467 };
1468 
1469 // Based on the basic test parameters, this function creates a number of sets/bindings that will be tested.
delayedInit()1470 void DescriptorBufferTestCase::delayedInit()
1471 {
1472     if ((m_params.variant == TestVariant::SINGLE) || (m_params.variant == TestVariant::CAPTURE_REPLAY) ||
1473         (m_params.variant == TestVariant::YCBCR_SAMPLER))
1474     {
1475         // Creates a single set with a single binding, unless additional helper resources are required.
1476         {
1477             SimpleBinding sb{};
1478             sb.set     = 0;
1479             sb.binding = 0;
1480             sb.type    = m_params.descriptor;
1481             sb.count   = 1;
1482 
1483             // For inline uniforms we still use count = 1. The byte size is implicit in our tests.
1484 
1485             m_simpleBindings.emplace_back(sb);
1486         }
1487 
1488         if (m_params.subcase == SubCase::YCBCR_SAMPLER_ARRAY)
1489         {
1490             // Add one more arrayed binding to ensure the descriptor offsets are as expected.
1491             SimpleBinding sb{};
1492             sb.set     = 0;
1493             sb.binding = u32(m_simpleBindings.size());
1494             sb.type    = m_params.descriptor;
1495             sb.count   = 2;
1496 
1497             m_simpleBindings.emplace_back(sb);
1498         }
1499 
1500         // Sampled images require a sampler as well.
1501         if (m_params.descriptor == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)
1502         {
1503             SimpleBinding sb{};
1504             sb.set     = 0;
1505             sb.binding = u32(m_simpleBindings.size());
1506             sb.type    = VK_DESCRIPTOR_TYPE_SAMPLER;
1507             sb.count   = 1;
1508 
1509             m_simpleBindings.emplace_back(sb);
1510         }
1511         else if (m_params.isCaptureReplayDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER))
1512         {
1513             // Samplers are usually tested implicitly, but with capture replay they are the target of specific API commands.
1514             // Add a sampled image to acompany the sampler.
1515 
1516             SimpleBinding sb{};
1517             sb.set     = 0;
1518             sb.binding = u32(m_simpleBindings.size());
1519             sb.type    = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
1520             sb.count   = 1;
1521 
1522             m_simpleBindings.emplace_back(sb);
1523         }
1524 
1525         // For compute shaders add a result buffer as the last binding of the first set.
1526         if (m_params.isCompute() || m_params.isRayTracing())
1527         {
1528             SimpleBinding sb{};
1529             sb.set            = 0;
1530             sb.binding        = u32(m_simpleBindings.size());
1531             sb.type           = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1532             sb.count          = 1;
1533             sb.isResultBuffer = true;
1534             sb.isRayTracingAS = false;
1535 
1536             m_simpleBindings.emplace_back(sb);
1537 
1538             if (m_params.isRayTracing())
1539             {
1540                 SimpleBinding sba{};
1541                 sba.set            = 0;
1542                 sba.binding        = u32(m_simpleBindings.size());
1543                 sba.type           = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
1544                 sba.count          = 1;
1545                 sba.isResultBuffer = false;
1546                 sba.isRayTracingAS = true;
1547 
1548                 m_simpleBindings.emplace_back(sba);
1549             }
1550         }
1551     }
1552     else if ((m_params.variant == TestVariant::MULTIPLE) || (m_params.variant == TestVariant::PUSH_DESCRIPTOR) ||
1553              (m_params.variant == TestVariant::PUSH_TEMPLATE) ||
1554              (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS) ||
1555              (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) ||
1556              (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE))
1557     {
1558         // Generate a descriptor set for each descriptor buffer binding.
1559         // Within a set, add bindings for each descriptor type. Bindings may have 1-3 array elements.
1560         // In this test we include sampler descriptors, they will be used with sampled images, if needed.
1561 
1562         // NOTE: For implementation simplicity, this test doesn't limit the number of descriptors accessed
1563         // in the shaders, which may not work on some implementations.
1564 
1565         // Don't overcomplicate the test logic
1566         DE_ASSERT(!m_params.isPushDescriptorTest() || (m_params.setsPerBuffer == 1));
1567 
1568         // Add one more set for push descriptors (if used)
1569         const auto numSets =
1570             (m_params.bufferBindingCount * m_params.setsPerBuffer) + (m_params.isPushDescriptorTest() ? 1 : 0);
1571         uint32_t attachmentIndex = 0;
1572 
1573         // One set per buffer binding
1574         for (uint32_t set = 0; set < numSets; ++set)
1575         {
1576             std::vector<VkDescriptorType> choiceDescriptors;
1577             choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
1578             choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
1579             choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
1580             choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1581 
1582             if (m_params.variant != TestVariant::ROBUST_BUFFER_ACCESS)
1583             {
1584                 choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_SAMPLER);
1585                 choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
1586                 choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
1587                 choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
1588 
1589                 if (m_params.variant != TestVariant::MUTABLE_DESCRIPTOR_TYPE &&
1590                     (m_params.variant != TestVariant::ROBUST_NULL_DESCRIPTOR ||
1591                      (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR && m_params.isAccelerationStructure())))
1592                 {
1593                     choiceDescriptors.emplace_back(
1594                         VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR); // will be replaced with VK_DESCRIPTOR_TYPE_STORAGE_BUFFER if unsupported
1595                 }
1596 
1597                 if ((m_params.variant != TestVariant::ROBUST_NULL_DESCRIPTOR) &&
1598                     (m_params.variant != TestVariant::MUTABLE_DESCRIPTOR_TYPE) &&
1599                     (!m_params.isPushDescriptorTest() || (set != m_params.pushDescriptorSetIndex)))
1600                 {
1601                     choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK);
1602                 }
1603 
1604                 if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
1605                 {
1606                     choiceDescriptors.emplace_back(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
1607                 }
1608             }
1609 
1610             // Randomize the order
1611             m_rng.shuffle(choiceDescriptors.begin(), choiceDescriptors.end());
1612 
1613             for (uint32_t binding = 0; binding < u32(choiceDescriptors.size()); ++binding)
1614             {
1615                 SimpleBinding sb{};
1616                 sb.set     = set;
1617                 sb.binding = binding;
1618                 sb.type    = choiceDescriptors[binding];
1619                 sb.count   = 1 + ((sb.type != VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ?
1620                                       m_rng.getUint32() % ConstMaxDescriptorArraySize :
1621                                       0);
1622 
1623                 // For inline uniforms we still use count = 1. The byte size is implicit in our tests.
1624 
1625                 if (sb.type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
1626                 {
1627                     sb.inputAttachmentIndex = attachmentIndex;
1628                     attachmentIndex += sb.count;
1629                 }
1630 
1631                 m_simpleBindings.emplace_back(sb);
1632             }
1633 
1634             // For compute shaders add a result buffer as the last binding of the first set.
1635             if (set == 0 && (m_params.isCompute() || m_params.isRayTracing()))
1636             {
1637                 SimpleBinding sb{};
1638                 sb.set            = set;
1639                 sb.binding        = u32(m_simpleBindings.size());
1640                 sb.type           = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1641                 sb.count          = 1;
1642                 sb.isResultBuffer = true;
1643                 sb.isRayTracingAS = false;
1644 
1645                 m_simpleBindings.emplace_back(sb);
1646 
1647                 if (m_params.isRayTracing())
1648                 {
1649                     SimpleBinding sba{};
1650                     sba.set            = set;
1651                     sba.binding        = u32(m_simpleBindings.size());
1652                     sba.type           = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
1653                     sba.count          = 1;
1654                     sba.isResultBuffer = false;
1655                     sba.isRayTracingAS = true;
1656 
1657                     m_simpleBindings.emplace_back(sba);
1658                 }
1659             }
1660         }
1661     }
1662     else if (m_params.variant == TestVariant::MAX)
1663     {
1664         // Create sampler- and resource-only sets, up to specified maxiumums.
1665         // Each set will get its own descriptor buffer binding.
1666 
1667         uint32_t set          = 0;
1668         uint32_t samplerIndex = 0;
1669         uint32_t imageIndex   = 0;
1670 
1671         for (;;)
1672         {
1673             SimpleBinding sb{};
1674             sb.binding = 0;
1675             sb.count   = 1;
1676             sb.set     = set; // save the original set index here
1677 
1678             if (samplerIndex < m_params.samplerBufferBindingCount)
1679             {
1680                 sb.set  = set;
1681                 sb.type = VK_DESCRIPTOR_TYPE_SAMPLER;
1682 
1683                 m_simpleBindings.emplace_back(sb);
1684 
1685                 ++set;
1686                 ++samplerIndex;
1687             }
1688 
1689             if (imageIndex < m_params.resourceBufferBindingCount)
1690             {
1691                 sb.set  = set;
1692                 sb.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
1693 
1694                 m_simpleBindings.emplace_back(sb);
1695 
1696                 // Put the result buffer in the first resource set
1697                 if ((imageIndex == 0) && (m_params.isCompute() || m_params.isRayTracing()))
1698                 {
1699                     sb.binding        = 1;
1700                     sb.type           = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1701                     sb.isResultBuffer = true;
1702 
1703                     m_simpleBindings.emplace_back(sb);
1704 
1705                     if (m_params.isRayTracing())
1706                     {
1707                         sb.binding        = 2;
1708                         sb.type           = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
1709                         sb.isResultBuffer = false;
1710                         sb.isRayTracingAS = true;
1711 
1712                         m_simpleBindings.emplace_back(sb);
1713                     }
1714                 }
1715 
1716                 ++set;
1717                 ++imageIndex;
1718             }
1719 
1720             if (sb.set == set)
1721             {
1722                 // We didn't add a new set, so we must be done.
1723                 break;
1724             }
1725         }
1726     }
1727     else if (m_params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
1728     {
1729         // Create a number of sampler-only sets across several descriptor buffers, they will be used as embedded
1730         // immutable sampler buffers. Finally, add a set with images that use these samplers.
1731 
1732         // Buffer index maps to a set with embedded immutable samplers
1733         for (uint32_t bufferIndex = 0; bufferIndex < m_params.embeddedImmutableSamplerBufferBindingCount; ++bufferIndex)
1734         {
1735             for (uint32_t samplerIndex = 0; samplerIndex < m_params.embeddedImmutableSamplersPerBuffer; ++samplerIndex)
1736             {
1737                 SimpleBinding sb{};
1738                 sb.set                        = bufferIndex;
1739                 sb.binding                    = samplerIndex;
1740                 sb.count                      = 1;
1741                 sb.type                       = VK_DESCRIPTOR_TYPE_SAMPLER;
1742                 sb.isEmbeddedImmutableSampler = true;
1743 
1744                 m_simpleBindings.emplace_back(sb);
1745             }
1746         }
1747 
1748         // After the samplers come the images
1749         if (!m_simpleBindings.empty())
1750         {
1751             SimpleBinding sb{};
1752             sb.set   = m_simpleBindings.back().set + 1;
1753             sb.count = 1;
1754 
1755             const auto numSamplers =
1756                 m_params.embeddedImmutableSamplerBufferBindingCount * m_params.embeddedImmutableSamplersPerBuffer;
1757 
1758             for (uint32_t samplerIndex = 0; samplerIndex < numSamplers; ++samplerIndex)
1759             {
1760                 sb.type    = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
1761                 sb.binding = samplerIndex;
1762 
1763                 m_simpleBindings.emplace_back(sb);
1764             }
1765 
1766             if (m_params.isCompute() || m_params.isRayTracing())
1767             {
1768                 // Append the result buffer after the images
1769                 sb.binding += 1;
1770                 sb.type           = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1771                 sb.isResultBuffer = true;
1772 
1773                 m_simpleBindings.emplace_back(sb);
1774 
1775                 if (m_params.isRayTracing())
1776                 {
1777                     sb.binding += 1;
1778                     sb.type           = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
1779                     sb.isResultBuffer = false;
1780                     sb.isRayTracingAS = true;
1781 
1782                     m_simpleBindings.emplace_back(sb);
1783                 }
1784             }
1785         }
1786     }
1787 }
1788 
1789 // Generate shaders for both acceleration structures and without them
initPrograms(vk::SourceCollections & programs) const1790 void DescriptorBufferTestCase::initPrograms(vk::SourceCollections &programs) const
1791 {
1792     const bool accStruct = m_params.isAccelerationStructureObligatory() || m_params.isAccelerationStructureOptional();
1793 
1794     initPrograms(programs, m_simpleBindings, accStruct, true);
1795 
1796     if (accStruct)
1797     {
1798         std::vector<SimpleBinding> simpleBindings(m_simpleBindings);
1799 
1800         for (auto &simpleBinding : simpleBindings)
1801             if (simpleBinding.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
1802                 simpleBinding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1803 
1804         initPrograms(programs, simpleBindings, false, false);
1805     }
1806 }
1807 
1808 // Initialize GLSL shaders used by all test cases.
initPrograms(vk::SourceCollections & programs,const std::vector<SimpleBinding> & simpleBindings,bool accStruct,bool addService) const1809 void DescriptorBufferTestCase::initPrograms(vk::SourceCollections &programs,
1810                                             const std::vector<SimpleBinding> &simpleBindings, bool accStruct,
1811                                             bool addService) const
1812 {
1813     // For vertex pipelines, a verification variable (in_result/out_result) is passed
1814     // through shader interfaces, until it can be output as a color write.
1815     //
1816     // Compute shaders still declare a "result" variable to help unify the verification logic.
1817     std::string extentionDeclarations = std::string(glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_460)) + "\n" +
1818                                         (m_params.isRayTracing() ? "#extension GL_EXT_ray_tracing : require\n" : "");
1819 
1820     if (m_params.isGraphics())
1821     {
1822         std::string srcDeclarations;
1823         std::string srcVerification;
1824         std::string suffix;
1825 
1826         if (m_params.stage == VK_SHADER_STAGE_VERTEX_BIT)
1827         {
1828             srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
1829             srcVerification = glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
1830             suffix          = accStruct ? "_as" : "";
1831         }
1832 
1833         std::ostringstream str;
1834         str << extentionDeclarations << srcDeclarations
1835             << "\n"
1836                "layout(location = 0) out uvec4 out_result;\n"
1837                "\n"
1838                "void main (void) {\n"
1839                "    switch(gl_VertexIndex) {\n"
1840                "        case 0: gl_Position = vec4(-1, -1, 0, 1); break;\n"
1841                "        case 1: gl_Position = vec4(-1,  1, 0, 1); break;\n"
1842                "        case 2: gl_Position = vec4( 1, -1, 0, 1); break;\n"
1843                "\n"
1844                "        case 3: gl_Position = vec4( 1,  1, 0, 1); break;\n"
1845                "        case 4: gl_Position = vec4( 1, -1, 0, 1); break;\n"
1846                "        case 5: gl_Position = vec4(-1,  1, 0, 1); break;\n"
1847                "    }\n"
1848                "\n"
1849                "    uvec4 result = uvec4(0);\n"
1850                "\n"
1851             << srcVerification
1852             << "\n"
1853                "    out_result = result;\n"
1854                "}\n";
1855 
1856         if (addService || !srcDeclarations.empty())
1857             programs.glslSources.add("vert" + suffix) << glu::VertexSource(str.str());
1858     }
1859 
1860     if (m_params.isGraphics())
1861     {
1862         std::string srcDeclarations;
1863         std::string srcVerification;
1864         std::string suffix;
1865 
1866         if (m_params.stage == VK_SHADER_STAGE_FRAGMENT_BIT)
1867         {
1868             srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
1869             srcVerification = glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
1870             suffix          = accStruct ? "_as" : "";
1871         }
1872 
1873         std::ostringstream str;
1874         str << extentionDeclarations << srcDeclarations
1875             << "\n"
1876                "layout(location = 0) in flat uvec4 in_result;\n"
1877                "\n"
1878                "layout(location = 0) out uint out_color;\n"
1879                "\n"
1880                "void main (void) {\n"
1881                "    uvec4 result = in_result;\n"
1882                "\n"
1883             << srcVerification
1884             << "\n"
1885                "    if (uint(gl_FragCoord.x) == 0)    out_color = result.x;\n"
1886                "    if (uint(gl_FragCoord.x) == 1)    out_color = result.y;\n"
1887                "    if (uint(gl_FragCoord.x) == 2)    out_color = result.z;\n"
1888                "    if (uint(gl_FragCoord.x) == 3)    out_color = result.w;\n"
1889                "}\n";
1890 
1891         if (addService || !srcDeclarations.empty())
1892             programs.glslSources.add("frag" + suffix) << glu::FragmentSource(str.str());
1893     }
1894 
1895     if (m_params.isGeometry())
1896     {
1897         std::string srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
1898         std::string srcVerification = glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
1899         std::string suffix          = accStruct ? "_as" : "";
1900 
1901         std::ostringstream str;
1902         str << extentionDeclarations << srcDeclarations
1903             << "\n"
1904                "layout(triangles) in;\n"
1905                "layout(triangle_strip, max_vertices = 3) out;\n"
1906                "\n"
1907                "layout(location = 0) in  uvec4 in_result[];\n"
1908                "layout(location = 0) out uvec4 out_result;\n"
1909                "\n"
1910                "void main (void) {\n"
1911                "    for (uint i = 0; i < gl_in.length(); ++i) {\n"
1912                "        gl_Position = gl_in[i].gl_Position;\n"
1913                "\n"
1914                "        uvec4 result = in_result[i];\n"
1915                "\n"
1916             << srcVerification
1917             << "\n"
1918                "        out_result = result;\n"
1919                "\n"
1920                "        EmitVertex();\n"
1921                "    }\n"
1922                "}\n";
1923 
1924         if (addService || !srcDeclarations.empty())
1925             programs.glslSources.add("geom" + suffix) << glu::GeometrySource(str.str());
1926     }
1927 
1928     if (m_params.isTessellation())
1929     {
1930         std::string srcDeclarations;
1931         std::string srcVerification;
1932         std::string suffix;
1933 
1934         if (m_params.stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
1935         {
1936             srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
1937             srcVerification = glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
1938             suffix          = accStruct ? "_as" : "";
1939         }
1940 
1941         std::ostringstream str;
1942         str << extentionDeclarations << "#extension GL_EXT_tessellation_shader : require\n"
1943             << srcDeclarations
1944             << "\n"
1945                "layout(vertices = 3) out;\n"
1946                "\n"
1947                "layout(location = 0) in  uvec4 in_result[];\n"
1948                "layout(location = 0) out uvec4 out_result[];\n"
1949                "\n"
1950                "void main (void) {\n"
1951                "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1952                "    \n"
1953                "    gl_TessLevelOuter[0] = 1.0;\n"
1954                "    gl_TessLevelOuter[1] = 1.0;\n"
1955                "    gl_TessLevelOuter[2] = 1.0;\n"
1956                "    gl_TessLevelInner[0] = 1.0;\n"
1957                "\n"
1958                "    uvec4 result = in_result[gl_InvocationID];\n"
1959                "\n"
1960             << srcVerification
1961             << "\n"
1962                "    out_result[gl_InvocationID] = result;\n"
1963                "}\n";
1964 
1965         if (addService || !srcDeclarations.empty())
1966             programs.glslSources.add("tesc" + suffix) << glu::TessellationControlSource(str.str());
1967     }
1968 
1969     if (m_params.isTessellation())
1970     {
1971         std::string srcDeclarations;
1972         std::string srcVerification;
1973         std::string suffix;
1974 
1975         if (m_params.stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
1976         {
1977             srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
1978             srcVerification = glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
1979             suffix          = accStruct ? "_as" : "";
1980         }
1981 
1982         std::ostringstream str;
1983         str << extentionDeclarations << "#extension GL_EXT_tessellation_shader : require\n"
1984             << srcDeclarations
1985             << "\n"
1986                "layout(triangles) in;\n"
1987                "\n"
1988                "layout(location = 0) in  uvec4 in_result[];\n"
1989                "layout(location = 0) out uvec4 out_result;\n"
1990                "\n"
1991                "void main (void) {\n"
1992                "    gl_Position.xyz = gl_TessCoord.x * gl_in[0].gl_Position.xyz +\n"
1993                "                      gl_TessCoord.y * gl_in[1].gl_Position.xyz +\n"
1994                "                      gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
1995                "    gl_Position.w   = 1.0;\n"
1996                "\n"
1997                "    uvec4 result = in_result[0];\n" // Use index 0, all vertices should have the same value
1998                "\n"
1999             << srcVerification
2000             << "\n"
2001                "    out_result = result;\n"
2002                "}\n";
2003 
2004         if (addService || !srcDeclarations.empty())
2005             programs.glslSources.add("tese" + suffix) << glu::TessellationEvaluationSource(str.str());
2006     }
2007 
2008     if (m_params.isCompute())
2009     {
2010         const std::string suffix = accStruct ? "_as" : "";
2011         std::ostringstream str;
2012         str << extentionDeclarations << glslGlobalDeclarations(m_params, simpleBindings, accStruct)
2013             << "\n"
2014                "layout(local_size_x = 1) in;\n"
2015                "\n"
2016                "void main (void) {\n"
2017                "    uvec4 result = uvec4(0);\n"
2018                "\n"
2019             << glslOutputVerification(m_params, simpleBindings, accStruct) << "}\n";
2020 
2021         programs.glslSources.add("comp" + suffix) << glu::ComputeSource(str.str());
2022     }
2023 
2024     if (m_params.isRayTracing())
2025     {
2026         const std::string missPassthrough = extentionDeclarations +
2027                                             "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
2028                                             "\n"
2029                                             "void main()\n"
2030                                             "{\n"
2031                                             "}\n";
2032         const std::string hitPassthrough = extentionDeclarations +
2033                                            "hitAttributeEXT vec3 attribs;\n"
2034                                            "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
2035                                            "\n"
2036                                            "void main()\n"
2037                                            "{\n"
2038                                            "}\n";
2039         const uint32_t asIndex         = getRayTracingASIndex(simpleBindings);
2040         const auto &asBinding          = simpleBindings[asIndex];
2041         const std::string asName       = glslResourceName(asBinding.set, asBinding.binding);
2042         const std::string raygenCommon = extentionDeclarations +
2043                                          "layout(location = 0) rayPayloadEXT vec3 hitValue;\n"
2044                                          "layout(set = " +
2045                                          de::toString(asBinding.set) +
2046                                          ", binding = " + de::toString(asBinding.binding) +
2047                                          ") uniform accelerationStructureEXT " + asName +
2048                                          ";\n"
2049                                          "\n"
2050                                          "void main()\n"
2051                                          "{\n"
2052                                          "    uint  rayFlags = 0;\n"
2053                                          "    uint  cullMask = 0xFF;\n"
2054                                          "    float tmin     = 0.0f;\n"
2055                                          "    float tmax     = 9.0f;\n"
2056                                          "    vec3  origin   = vec3(0.0f, 0.0f, 0.0f);\n"
2057                                          "    vec3  direct   = vec3(0.0f, 0.0f, -1.0f);\n"
2058                                          "    traceRayEXT(" +
2059                                          asName +
2060                                          ", rayFlags, cullMask, 0, 0, 0, origin, tmin, direct, tmax, 0);\n"
2061                                          "}\n";
2062         const vk::ShaderBuildOptions buildOptions =
2063             vk::ShaderBuildOptions(programs.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
2064         const std::string suffix          = accStruct ? "_as" : "";
2065         const std::string srcDeclarations = glslGlobalDeclarations(m_params, simpleBindings, accStruct) + "\n";
2066         const std::string srcVerification =
2067             "    uvec4 result = uvec4(0);\n" + glslOutputVerification(m_params, simpleBindings, accStruct) + "\n";
2068 
2069         switch (m_params.stage)
2070         {
2071         case VK_SHADER_STAGE_RAYGEN_BIT_KHR:
2072         {
2073             std::stringstream css;
2074             css << extentionDeclarations << "\n"
2075                 << srcDeclarations
2076                 << "\n"
2077                    "void main()\n"
2078                    "{\n"
2079                 << srcVerification << "}\n";
2080 
2081             programs.glslSources.add("rgen" + suffix) << glu::RaygenSource(css.str()) << buildOptions;
2082 
2083             break;
2084         }
2085 
2086         case VK_SHADER_STAGE_ANY_HIT_BIT_KHR:
2087         {
2088             if (addService)
2089                 programs.glslSources.add("rgen") << glu::RaygenSource(raygenCommon) << buildOptions;
2090 
2091             {
2092                 std::stringstream css;
2093                 css << extentionDeclarations << "\n"
2094                     << srcDeclarations
2095                     << "hitAttributeEXT vec3 attribs;\n"
2096                        "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
2097                        "\n"
2098                        "void main()\n"
2099                        "{\n"
2100                     << srcVerification << "}\n";
2101 
2102                 programs.glslSources.add("ahit" + suffix) << glu::AnyHitSource(css.str()) << buildOptions;
2103             }
2104 
2105             if (addService)
2106                 programs.glslSources.add("chit") << glu::ClosestHitSource(hitPassthrough) << buildOptions;
2107             if (addService)
2108                 programs.glslSources.add("miss") << glu::MissSource(missPassthrough) << buildOptions;
2109 
2110             break;
2111         }
2112 
2113         case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR:
2114         {
2115             if (addService)
2116                 programs.glslSources.add("rgen") << glu::RaygenSource(raygenCommon) << buildOptions;
2117 
2118             {
2119                 std::stringstream css;
2120                 css << extentionDeclarations << "\n"
2121                     << srcDeclarations
2122                     << "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
2123                        "hitAttributeEXT vec3 attribs;\n"
2124                        "\n"
2125                        "\n"
2126                        "void main()\n"
2127                        "{\n"
2128                     << srcVerification << "}\n";
2129 
2130                 programs.glslSources.add("chit" + suffix) << glu::ClosestHitSource(css.str()) << buildOptions;
2131             }
2132 
2133             if (addService)
2134                 programs.glslSources.add("ahit") << glu::AnyHitSource(hitPassthrough) << buildOptions;
2135             if (addService)
2136                 programs.glslSources.add("miss") << glu::MissSource(missPassthrough) << buildOptions;
2137 
2138             break;
2139         }
2140 
2141         case VK_SHADER_STAGE_INTERSECTION_BIT_KHR:
2142         {
2143             if (addService)
2144                 programs.glslSources.add("rgen") << glu::RaygenSource(raygenCommon) << buildOptions;
2145 
2146             {
2147                 std::stringstream css;
2148                 css << extentionDeclarations << "\n"
2149                     << srcDeclarations
2150                     << "hitAttributeEXT vec3 hitAttribute;\n"
2151                        "\n"
2152                        "void main()\n"
2153                        "{\n"
2154                     << srcVerification
2155                     << "    hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n"
2156                        "    reportIntersectionEXT(1.0f, 0);\n"
2157                        "}\n";
2158 
2159                 programs.glslSources.add("sect" + suffix) << glu::IntersectionSource(css.str()) << buildOptions;
2160             }
2161 
2162             if (addService)
2163                 programs.glslSources.add("ahit") << glu::AnyHitSource(hitPassthrough) << buildOptions;
2164             if (addService)
2165                 programs.glslSources.add("chit") << glu::ClosestHitSource(hitPassthrough) << buildOptions;
2166             if (addService)
2167                 programs.glslSources.add("miss") << glu::MissSource(missPassthrough) << buildOptions;
2168 
2169             break;
2170         }
2171 
2172         case VK_SHADER_STAGE_MISS_BIT_KHR:
2173         {
2174             if (addService)
2175                 programs.glslSources.add("rgen") << glu::RaygenSource(raygenCommon) << buildOptions;
2176 
2177             {
2178                 std::stringstream css;
2179                 css << extentionDeclarations << "\n"
2180                     << srcDeclarations
2181                     << "\n"
2182                        "layout(location = 0) rayPayloadInEXT vec3 hitValue;\n"
2183                        "\n"
2184                        "void main()\n"
2185                        "{\n"
2186                     << srcVerification << "}\n";
2187 
2188                 programs.glslSources.add("miss" + suffix) << glu::MissSource(css.str()) << buildOptions;
2189             }
2190 
2191             if (addService)
2192                 programs.glslSources.add("ahit") << glu::AnyHitSource(hitPassthrough) << buildOptions;
2193             if (addService)
2194                 programs.glslSources.add("chit") << glu::ClosestHitSource(hitPassthrough) << buildOptions;
2195 
2196             break;
2197         }
2198 
2199         case VK_SHADER_STAGE_CALLABLE_BIT_KHR:
2200         {
2201             {
2202                 std::stringstream css;
2203                 css << extentionDeclarations << "\n"
2204                     << (accStruct ? "#extension GL_EXT_ray_query : require\n" : "")
2205                     << "\n"
2206                        "layout(location = 0) callableDataEXT float dummy;"
2207                        "\n"
2208                        "void main()\n"
2209                        "{\n"
2210                        "    executeCallableEXT(0, 0);\n"
2211                        "}\n";
2212 
2213                 if (addService)
2214                     programs.glslSources.add("rgen") << glu::RaygenSource(css.str()) << buildOptions;
2215             }
2216 
2217             {
2218                 std::stringstream css;
2219                 css << extentionDeclarations << "\n"
2220                     << srcDeclarations
2221                     << "\n"
2222                        "layout(location = 0) callableDataInEXT float dummy;"
2223                        "\n"
2224                        "void main()\n"
2225                        "{\n"
2226                     << srcVerification << "}\n";
2227 
2228                 programs.glslSources.add("call" + suffix) << glu::CallableSource(css.str()) << buildOptions;
2229             }
2230 
2231             if (addService)
2232                 programs.glslSources.add("ahit") << glu::AnyHitSource(hitPassthrough) << buildOptions;
2233             if (addService)
2234                 programs.glslSources.add("chit") << glu::ClosestHitSource(hitPassthrough) << buildOptions;
2235             if (addService)
2236                 programs.glslSources.add("miss") << glu::MissSource(missPassthrough) << buildOptions;
2237 
2238             break;
2239         }
2240 
2241         default:
2242             TCU_THROW(InternalError, "Unknown stage");
2243         }
2244     }
2245 }
2246 
checkSupport(Context & context) const2247 void DescriptorBufferTestCase::checkSupport(Context &context) const
2248 {
2249     // Required to test the extension
2250     if (!context.isDeviceFunctionalitySupported("VK_EXT_descriptor_buffer"))
2251     {
2252         TCU_THROW(NotSupportedError, "VK_EXT_descriptor_buffer is not supported");
2253     }
2254 
2255     if (!context.isInstanceFunctionalitySupported("VK_KHR_get_physical_device_properties2"))
2256     {
2257         TCU_THROW(NotSupportedError, "VK_KHR_get_physical_device_properties2 is not supported");
2258     }
2259 
2260     if (!context.isDeviceFunctionalitySupported("VK_KHR_buffer_device_address"))
2261     {
2262         TCU_THROW(NotSupportedError, "VK_KHR_buffer_device_address is not supported");
2263     }
2264 
2265     if (!context.isDeviceFunctionalitySupported("VK_KHR_synchronization2"))
2266     {
2267         TCU_THROW(NotSupportedError, "VK_KHR_synchronization2 is not supported");
2268     }
2269 
2270     if (!context.isDeviceFunctionalitySupported("VK_EXT_descriptor_indexing"))
2271     {
2272         TCU_THROW(NotSupportedError, "VK_EXT_descriptor_indexing is not supported");
2273     }
2274 
2275     context.requireDeviceFunctionality("VK_KHR_buffer_device_address");
2276     context.requireDeviceFunctionality("VK_KHR_maintenance4");
2277     if (m_params.useMaintenance5)
2278         context.requireDeviceFunctionality("VK_KHR_maintenance5");
2279 
2280     // Optional
2281 
2282     if ((m_params.descriptor == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) &&
2283         !context.isDeviceFunctionalitySupported("VK_EXT_inline_uniform_block"))
2284     {
2285         TCU_THROW(NotSupportedError, "VK_EXT_inline_uniform_block is not supported");
2286     }
2287 
2288     const auto &descriptorBufferFeatures =
2289         *findStructure<VkPhysicalDeviceDescriptorBufferFeaturesEXT>(&context.getDeviceFeatures2());
2290     const auto &descriptorBufferProps =
2291         *findStructure<VkPhysicalDeviceDescriptorBufferPropertiesEXT>(&context.getDeviceProperties2());
2292 
2293     if (!descriptorBufferFeatures.descriptorBuffer)
2294     {
2295         TCU_THROW(NotSupportedError, "descriptorBufferFeatures.descriptorBuffer is not supported");
2296     }
2297 
2298     if (m_params.variant == TestVariant::CAPTURE_REPLAY)
2299     {
2300         if (descriptorBufferFeatures.descriptorBufferCaptureReplay == VK_FALSE)
2301         {
2302             TCU_THROW(NotSupportedError, "descriptorBufferCaptureReplay feature is not supported");
2303         }
2304 
2305         if ((m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR) &&
2306             !context.isDeviceFunctionalitySupported("VK_EXT_custom_border_color"))
2307         {
2308             TCU_THROW(NotSupportedError, "VK_EXT_custom_border_color is not supported");
2309         }
2310     }
2311 
2312     if (m_params.isTessellation() && (context.getDeviceFeatures().tessellationShader == VK_FALSE))
2313     {
2314         TCU_THROW(NotSupportedError, "tessellationShader feature is not supported");
2315     }
2316     else if (m_params.isGeometry() && (context.getDeviceFeatures().geometryShader == VK_FALSE))
2317     {
2318         TCU_THROW(NotSupportedError, "geometryShader feature is not supported");
2319     }
2320 
2321     if (m_params.bufferBindingCount * m_params.setsPerBuffer >
2322         context.getDeviceProperties().limits.maxBoundDescriptorSets)
2323         TCU_THROW(NotSupportedError, "Test requires more descriptor sets than specified in maxBoundDescriptorSets");
2324 
2325     // Test case specific
2326     if (m_params.isPushDescriptorTest())
2327     {
2328         context.requireDeviceFunctionality("VK_KHR_push_descriptor");
2329 
2330         if (descriptorBufferFeatures.descriptorBufferPushDescriptors == VK_FALSE)
2331         {
2332             TCU_THROW(NotSupportedError, "Require descriptorBufferFeatures.descriptorBufferPushDescriptors");
2333         }
2334 
2335         if (m_params.bufferBindingCount + 1 > context.getDeviceProperties().limits.maxBoundDescriptorSets)
2336             TCU_THROW(NotSupportedError, "Test requires more descriptor sets than specified in maxBoundDescriptorSets");
2337 
2338         if (m_params.subcase == SubCase::SINGLE_BUFFER)
2339         {
2340             if (descriptorBufferProps.bufferlessPushDescriptors)
2341                 TCU_THROW(NotSupportedError, "Require bufferlessPushDescriptors to be false");
2342         }
2343         else
2344         {
2345             if (m_params.samplerBufferBindingCount + 1 > descriptorBufferProps.maxSamplerDescriptorBufferBindings)
2346             {
2347                 TCU_THROW(NotSupportedError, "maxSamplerDescriptorBufferBindings is too small");
2348             }
2349 
2350             if (m_params.resourceBufferBindingCount + 1 > descriptorBufferProps.maxResourceDescriptorBufferBindings)
2351             {
2352                 TCU_THROW(NotSupportedError, "maxResourceDescriptorBufferBindings is too small");
2353             }
2354         }
2355     }
2356 
2357     if (m_params.bufferBindingCount > descriptorBufferProps.maxDescriptorBufferBindings)
2358     {
2359         TCU_THROW(NotSupportedError, "maxDescriptorBufferBindings is too small");
2360     }
2361 
2362     if (m_params.samplerBufferBindingCount > descriptorBufferProps.maxSamplerDescriptorBufferBindings)
2363     {
2364         TCU_THROW(NotSupportedError, "maxSamplerDescriptorBufferBindings is too small");
2365     }
2366 
2367     if (m_params.resourceBufferBindingCount > descriptorBufferProps.maxResourceDescriptorBufferBindings)
2368     {
2369         TCU_THROW(NotSupportedError, "maxResourceDescriptorBufferBindings is too small");
2370     }
2371 
2372     if ((m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS) ||
2373         (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR))
2374     {
2375         if (context.isDeviceFunctionalitySupported("VK_EXT_robustness2"))
2376         {
2377             VkPhysicalDeviceFeatures2 features2                        = initVulkanStructure();
2378             VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure();
2379 
2380             features2.pNext = &robustness2Features;
2381 
2382             context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
2383 
2384             if ((m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) &&
2385                 (robustness2Features.nullDescriptor == VK_FALSE))
2386             {
2387                 TCU_THROW(NotSupportedError, "robustness2 nullDescriptor is not supported");
2388             }
2389 
2390             DE_ASSERT(features2.features.robustBufferAccess);
2391         }
2392         else if (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR)
2393         {
2394             TCU_THROW(NotSupportedError, "VK_EXT_robustness2 is not supported");
2395         }
2396         else if (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS)
2397         {
2398             VkPhysicalDeviceFeatures features{};
2399             context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &features);
2400 
2401             if (features.robustBufferAccess == VK_FALSE)
2402             {
2403                 TCU_THROW(NotSupportedError, "robustBufferAccess is not supported");
2404             }
2405         }
2406     }
2407     else if ((m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE) &&
2408              !context.isDeviceFunctionalitySupported("VK_EXT_mutable_descriptor_type"))
2409     {
2410         TCU_THROW(NotSupportedError, "VK_EXT_mutable_descriptor_type is not supported");
2411     }
2412 
2413     if ((m_params.descriptor == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ||
2414         (m_params.variant == TestVariant::MULTIPLE) || m_params.isPushDescriptorTest())
2415     {
2416         const auto &inlineUniformBlockFeatures = context.getInlineUniformBlockFeatures();
2417 
2418         if (!inlineUniformBlockFeatures.inlineUniformBlock)
2419         {
2420             TCU_THROW(NotSupportedError, "inlineUniformBlock is required");
2421         }
2422     }
2423 
2424     if (m_params.variant == TestVariant::MULTIPLE)
2425     {
2426         const VkPhysicalDeviceVulkan13Properties &vulkan13properties =
2427             *findStructure<VkPhysicalDeviceVulkan13Properties>(&context.getDeviceVulkan13Properties());
2428 
2429         if (m_params.bufferBindingCount > vulkan13properties.maxPerStageDescriptorInlineUniformBlocks)
2430             TCU_THROW(NotSupportedError, "Test require more per-stage inline uniform block bindings count. Provided " +
2431                                              de::toString(vulkan13properties.maxPerStageDescriptorInlineUniformBlocks));
2432 
2433         if (m_params.bufferBindingCount > vulkan13properties.maxDescriptorSetInlineUniformBlocks)
2434             TCU_THROW(NotSupportedError, "Test require more inline uniform block bindings among all stages. Provided " +
2435                                              de::toString(vulkan13properties.maxDescriptorSetInlineUniformBlocks));
2436 
2437         if (m_params.bufferBindingCount > vulkan13properties.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks)
2438             TCU_THROW(NotSupportedError,
2439                       "Test require more per-stage inline uniform block bindings count. Provided " +
2440                           de::toString(vulkan13properties.maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks));
2441 
2442         if (m_params.bufferBindingCount > vulkan13properties.maxDescriptorSetUpdateAfterBindInlineUniformBlocks)
2443             TCU_THROW(NotSupportedError,
2444                       "Test require more inline uniform block bindings among all stages. Provided " +
2445                           de::toString(vulkan13properties.maxDescriptorSetUpdateAfterBindInlineUniformBlocks));
2446     }
2447 
2448     if (m_params.isAccelerationStructureObligatory())
2449     {
2450         context.requireDeviceFunctionality("VK_KHR_ray_query");
2451     }
2452 
2453     if (m_params.isRayTracing())
2454     {
2455         context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2456         context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
2457     }
2458 
2459     if ((m_params.variant == TestVariant::YCBCR_SAMPLER) &&
2460         !context.isDeviceFunctionalitySupported("VK_KHR_sampler_ycbcr_conversion"))
2461     {
2462         TCU_THROW(NotSupportedError, "VK_KHR_sampler_ycbcr_conversion is not supported");
2463     }
2464 
2465     if (m_params.commands2)
2466     {
2467         context.requireDeviceFunctionality("VK_KHR_maintenance6");
2468     }
2469 }
2470 
2471 // The base class for all test case implementations.
2472 class DescriptorBufferTestInstance : public TestInstance
2473 {
2474 public:
2475     DescriptorBufferTestInstance(Context &context, const TestParams &params,
2476                                  const std::vector<SimpleBinding> &simpleBindings);
2477 
2478     tcu::TestStatus iterate() override;
2479 
2480     void createRayTracingPipeline();
2481     de::MovePtr<BufferWithMemory> createShaderBindingTable(const InstanceInterface &vki, const DeviceInterface &vkd,
2482                                                            const VkDevice device, const VkPhysicalDevice physicalDevice,
2483                                                            const VkPipeline pipeline, Allocator &allocator,
2484                                                            de::MovePtr<RayTracingPipeline> &rayTracingPipeline,
2485                                                            const uint32_t group);
2486     void addRayTracingShader(const VkShaderStageFlagBits stage, const uint32_t group);
2487 
2488     void createGraphicsPipeline();
2489     void createDescriptorSetLayouts();
2490     void createDescriptorBuffers();
2491 
2492     void initializeBinding(const DescriptorSetLayoutHolder &dsl, uint32_t setIndex, Binding &binding);
2493 
2494     void pushDescriptorSet(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint, const DescriptorSetLayoutHolder &dsl,
2495                            uint32_t setIndex) const;
2496 
2497     void bindDescriptorBuffers(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint) const;
2498 
2499     void createBufferForBinding(ResourceHolder &resources, VkDescriptorType descriptorType,
2500                                 VkBufferCreateInfo createInfo, bool isResultBuffer) const;
2501 
2502     void createImageForBinding(ResourceHolder &resources, VkDescriptorType descriptorType) const;
2503 
allocate(const VkMemoryRequirements & memReqs,const MemoryRequirement requirement,const void * pNext=nullptr) const2504     MovePtr<Allocation> allocate(const VkMemoryRequirements &memReqs, const MemoryRequirement requirement,
2505                                  const void *pNext = nullptr) const
2506     {
2507         return allocateExtended(m_context.getInstanceInterface(), *m_deviceInterface, m_context.getPhysicalDevice(),
2508                                 *m_device, memReqs, requirement, pNext);
2509     }
2510 
2511     // Descriptor size is used to determine the stride of a descriptor array (for bindings with multiple descriptors).
2512     VkDeviceSize getDescriptorSize(const Binding &binding) const;
2513     VkDeviceSize getDescriptorTypeSize(VkDescriptorType descriptorType) const;
2514 
addDescriptorSetLayout()2515     uint32_t addDescriptorSetLayout()
2516     {
2517         m_descriptorSetLayouts.emplace_back(makeSharedUniquePtr<DescriptorSetLayoutHolder>());
2518         return u32(m_descriptorSetLayouts.size()) - 1;
2519     }
2520 
2521     // The resources used by descriptors are tracked in a simple array and referenced by an index.
addResource()2522     uint32_t addResource()
2523     {
2524         m_resources.emplace_back(makeSharedUniquePtr<ResourceHolder>());
2525         return u32(m_resources.size()) - 1;
2526     }
2527 
getOrCreateResource(Binding & binding,uint32_t arrayIndex)2528     ResourceHolder &getOrCreateResource(Binding &binding, uint32_t arrayIndex)
2529     {
2530         if (binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID)
2531         {
2532             binding.perBindingResourceIndex[arrayIndex] = addResource();
2533         }
2534 
2535         ResourceHolder &result = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]);
2536 
2537         return result;
2538     }
2539 
getShaderName(const VkShaderStageFlagBits stage) const2540     const std::string getShaderName(const VkShaderStageFlagBits stage) const
2541     {
2542         return toString(stage) + (m_params.isAccelerationStructure() && (m_params.stage == stage) ? "_as" : "");
2543     }
2544 
getShaderBinary(const VkShaderStageFlagBits stage) const2545     const ProgramBinary &getShaderBinary(const VkShaderStageFlagBits stage) const
2546     {
2547         return m_context.getBinaryCollection().get(getShaderName(stage));
2548     }
2549 
isCaptureDescriptor(VkDescriptorType type) const2550     bool isCaptureDescriptor(VkDescriptorType type) const
2551     {
2552         return (m_testIteration == 0) && m_params.isCaptureReplayDescriptor(type);
2553     }
2554 
isReplayDescriptor(VkDescriptorType type) const2555     bool isReplayDescriptor(VkDescriptorType type) const
2556     {
2557         return (m_testIteration == 1) && m_params.isCaptureReplayDescriptor(type);
2558     }
2559 
2560     // Test cases using compute shaders always declare one binding with a result buffer.
getResultBuffer() const2561     const BufferAlloc &getResultBuffer() const
2562     {
2563         DE_ASSERT(m_params.isCompute() || m_params.isRayTracing());
2564 
2565         const uint32_t resultBufferIndex = getResultBufferIndex(m_simpleBindings);
2566         DE_ASSERT(resultBufferIndex != INDEX_INVALID);
2567         const auto &sb = m_simpleBindings[resultBufferIndex];
2568 
2569         const auto binding = std::find_if((**m_descriptorSetLayouts[sb.set]).bindings.begin(),
2570                                           (**m_descriptorSetLayouts[sb.set]).bindings.end(),
2571                                           [&sb](const Binding &it) { return it.binding == sb.binding; });
2572 
2573         DE_ASSERT(binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2574 
2575         // There's only one result buffer at this binding
2576         return (**m_resources[binding->perBindingResourceIndex[0]]).buffer;
2577     }
2578 
2579 protected:
2580     TestParams m_params;
2581     std::vector<SimpleBinding> m_simpleBindings;
2582 
2583     Move<VkDevice> m_device;
2584     MovePtr<DeviceDriver> m_deviceInterface;
2585     VkQueue m_queue;
2586     uint32_t m_queueFamilyIndex;
2587     MovePtr<Allocator> m_allocatorPtr;
2588 
2589     VkPhysicalDeviceMemoryProperties m_memoryProperties;
2590     VkPhysicalDeviceDescriptorBufferFeaturesEXT m_descriptorBufferFeatures;
2591     VkPhysicalDeviceDescriptorBufferPropertiesEXT m_descriptorBufferProperties;
2592 
2593     Move<VkPipeline> m_pipeline;
2594     Move<VkPipelineLayout> m_pipelineLayout;
2595 
2596     // Optional, for graphics pipelines
2597     Move<VkFramebuffer> m_framebuffer;
2598     Move<VkRenderPass> m_renderPass;
2599     VkRect2D m_renderArea;
2600     ImageAlloc m_colorImage;
2601     BufferAlloc m_colorBuffer; // for copying back to host visible memory
2602 
2603     std::vector<DSLPtr> m_descriptorSetLayouts;
2604     std::vector<BufferAllocPtr> m_descriptorBuffers;
2605     BufferAlloc m_descriptorStagingBuffer;
2606 
2607     // Ray Tracing fields
2608     uint32_t m_shaders;
2609     uint32_t m_raygenShaderGroup;
2610     uint32_t m_missShaderGroup;
2611     uint32_t m_hitShaderGroup;
2612     uint32_t m_callableShaderGroup;
2613     uint32_t m_shaderGroupCount;
2614 
2615     de::MovePtr<RayTracingPipeline> m_rayTracingPipeline;
2616 
2617     de::MovePtr<BufferWithMemory> m_raygenShaderBindingTable;
2618     de::MovePtr<BufferWithMemory> m_hitShaderBindingTable;
2619     de::MovePtr<BufferWithMemory> m_missShaderBindingTable;
2620     de::MovePtr<BufferWithMemory> m_callableShaderBindingTable;
2621 
2622     VkStridedDeviceAddressRegionKHR m_raygenShaderBindingTableRegion;
2623     VkStridedDeviceAddressRegionKHR m_missShaderBindingTableRegion;
2624     VkStridedDeviceAddressRegionKHR m_hitShaderBindingTableRegion;
2625     VkStridedDeviceAddressRegionKHR m_callableShaderBindingTableRegion;
2626 
2627     de::SharedPtr<BottomLevelAccelerationStructure> m_bottomLevelAccelerationStructure;
2628     de::SharedPtr<TopLevelAccelerationStructure> m_topLevelAccelerationStructure;
2629 
2630     // Optional, ycbcr conversion test
2631     VkFormat m_imageColorFormat;
2632     uint32_t m_combinedImageSamplerDescriptorCount;
2633 
2634     // Common, but last
2635     std::vector<ResourcePtr> m_resources; // various resources used to test the descriptors
2636     uint32_t m_testIteration;             // for multi-pass tests such as capture/replay
2637 };
2638 
DescriptorBufferTestInstance(Context & context,const TestParams & params,const std::vector<SimpleBinding> & simpleBindings)2639 DescriptorBufferTestInstance::DescriptorBufferTestInstance(Context &context, const TestParams &params,
2640                                                            const std::vector<SimpleBinding> &simpleBindings)
2641     : TestInstance(context)
2642     , m_params(params)
2643     , m_simpleBindings(simpleBindings)
2644     , m_device()
2645     , m_deviceInterface()
2646     , m_queue()
2647     , m_queueFamilyIndex()
2648     , m_allocatorPtr(DE_NULL)
2649     , m_memoryProperties()
2650     , m_descriptorBufferFeatures()
2651     , m_descriptorBufferProperties()
2652     , m_pipeline()
2653     , m_pipelineLayout()
2654     , m_framebuffer()
2655     , m_renderPass()
2656     , m_renderArea(makeRect2D(0, 0, 4, 2)) // 4x2 to support _420 format, if needed
2657     , m_colorImage()
2658     , m_colorBuffer()
2659     , m_descriptorSetLayouts()
2660     , m_descriptorBuffers()
2661     , m_descriptorStagingBuffer()
2662     , m_shaders(0)
2663     , m_raygenShaderGroup(~0u)
2664     , m_missShaderGroup(~0u)
2665     , m_hitShaderGroup(~0u)
2666     , m_callableShaderGroup(~0u)
2667     , m_shaderGroupCount(0)
2668     , m_rayTracingPipeline(DE_NULL)
2669     , m_raygenShaderBindingTable()
2670     , m_hitShaderBindingTable()
2671     , m_missShaderBindingTable()
2672     , m_callableShaderBindingTable()
2673     , m_raygenShaderBindingTableRegion()
2674     , m_missShaderBindingTableRegion()
2675     , m_hitShaderBindingTableRegion()
2676     , m_callableShaderBindingTableRegion()
2677     , m_bottomLevelAccelerationStructure()
2678     , m_topLevelAccelerationStructure()
2679     , m_imageColorFormat()
2680     , m_combinedImageSamplerDescriptorCount(1)
2681     , m_resources()
2682     , m_testIteration(0)
2683 {
2684     // Need to create a new device because:
2685     // - We want to test graphics and compute queues,
2686     // - We must exclude VK_AMD_shader_fragment_mask from the enabled extensions.
2687 
2688     if (m_params.isAccelerationStructure() && m_params.isAccelerationStructureOptional())
2689     {
2690         if (!m_context.getRayQueryFeatures().rayQuery)
2691         {
2692             // Disable testing of acceleration structures if they ray query is not supported
2693             m_params.descriptor = VK_DESCRIPTOR_TYPE_MAX_ENUM;
2694 
2695             // Replace acceleration structures with storage buffers
2696             for (auto &simpleBinding : m_simpleBindings)
2697                 if ((simpleBinding.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) &&
2698                     !simpleBinding.isRayTracingAS)
2699                     simpleBinding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
2700         }
2701         else
2702         {
2703             context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2704         }
2705     }
2706 
2707     if ((m_params.variant == TestVariant::MULTIPLE) || (m_params.variant == TestVariant::PUSH_DESCRIPTOR) ||
2708         (m_params.variant == TestVariant::PUSH_TEMPLATE) || (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS) ||
2709         (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR))
2710     {
2711         const vk::VkPhysicalDeviceLimits &limits = context.getDeviceProperties().limits;
2712         uint32_t maxPerStageDescriptorSamplers =
2713             0; // VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
2714         uint32_t maxPerStageDescriptorUniformBuffers = 0; // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
2715         uint32_t maxPerStageDescriptorStorageBuffers = 0; // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
2716         uint32_t maxPerStageDescriptorSampledImages =
2717             0; // VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, or VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
2718         uint32_t maxPerStageDescriptorStorageImages =
2719             0; // VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
2720         uint32_t maxPerStageDescriptorInputAttachments = 0; // VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
2721 
2722         for (const auto &simpleBinding : m_simpleBindings)
2723         {
2724             switch (simpleBinding.type)
2725             {
2726             case VK_DESCRIPTOR_TYPE_SAMPLER:
2727                 maxPerStageDescriptorSamplers += simpleBinding.count;
2728                 break;
2729             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2730                 maxPerStageDescriptorSamplers += simpleBinding.count;
2731                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2732                 break;
2733             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2734                 maxPerStageDescriptorUniformBuffers += simpleBinding.count;
2735                 break;
2736             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2737                 maxPerStageDescriptorStorageBuffers += simpleBinding.count;
2738                 break;
2739             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2740                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2741                 break;
2742             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2743                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2744                 break;
2745             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2746                 maxPerStageDescriptorStorageImages += simpleBinding.count;
2747                 break;
2748             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2749                 maxPerStageDescriptorStorageImages += simpleBinding.count;
2750                 break;
2751             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2752                 maxPerStageDescriptorInputAttachments += simpleBinding.count;
2753                 break;
2754             default:
2755                 break;
2756             }
2757         }
2758 
2759 #define VALIDATE_PER_STAGE_LIMIT(NAME)                                                                           \
2760     if (NAME > limits.NAME)                                                                                      \
2761         TCU_THROW(NotSupportedError, std::string(#NAME) + " " + de::toString(NAME) + " is greater than limit " + \
2762                                          de::toString(limits.NAME));
2763         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorSamplers);
2764         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorUniformBuffers);
2765         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorStorageBuffers);
2766         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorSampledImages);
2767         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorStorageImages);
2768         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorInputAttachments);
2769 #undef VALIDATE_PER_STAGE_LIMIT
2770     }
2771 
2772     auto &inst      = context.getInstanceInterface();
2773     auto physDevice = context.getPhysicalDevice();
2774     auto queueProps = getPhysicalDeviceQueueFamilyProperties(inst, physDevice);
2775 
2776     m_queueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2777 
2778     uint32_t graphicsComputeQueue = VK_QUEUE_FAMILY_IGNORED;
2779 
2780     for (uint32_t i = 0; i < queueProps.size(); ++i)
2781     {
2782         if (m_params.queue == VK_QUEUE_GRAPHICS_BIT)
2783         {
2784             if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
2785             {
2786                 m_queueFamilyIndex = i;
2787 
2788                 break;
2789             }
2790         }
2791         else if (m_params.queue == VK_QUEUE_COMPUTE_BIT)
2792         {
2793             if (((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) &&
2794                 ((queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0))
2795             {
2796                 m_queueFamilyIndex = i;
2797             }
2798             else if (((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) &&
2799                      ((queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0))
2800             {
2801                 graphicsComputeQueue = i;
2802             }
2803         }
2804     }
2805 
2806     // If a compute only queue could not be found, fall back to a
2807     // graphics & compute one.
2808     if (m_params.queue == VK_QUEUE_COMPUTE_BIT && m_queueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
2809     {
2810         m_queueFamilyIndex = graphicsComputeQueue;
2811     }
2812 
2813     if (m_queueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
2814     {
2815         TCU_THROW(NotSupportedError, "Queue not supported");
2816     }
2817 
2818     const float priority[1] = {0.5f};
2819 
2820     VkDeviceQueueCreateInfo queueInfo = initVulkanStructure();
2821     queueInfo.queueFamilyIndex        = m_queueFamilyIndex;
2822     queueInfo.queueCount              = 1;
2823     queueInfo.pQueuePriorities        = priority;
2824 
2825     VkPhysicalDeviceFeatures2 features2                                            = initVulkanStructure();
2826     VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufferFeatures           = initVulkanStructure();
2827     VkPhysicalDeviceInlineUniformBlockFeaturesEXT inlineUniformBlockFeatures       = initVulkanStructure();
2828     VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features           = initVulkanStructure();
2829     VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features                     = initVulkanStructure();
2830     VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutableDescTypeFeatures       = initVulkanStructure();
2831     VkPhysicalDeviceCustomBorderColorFeaturesEXT customBorderColorFeatures         = initVulkanStructure();
2832     VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR samplerYcbcrConvFeatures     = initVulkanStructure();
2833     VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures = initVulkanStructure();
2834     VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures                           = initVulkanStructure();
2835     VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures       = initVulkanStructure();
2836     VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddressFeatures        = initVulkanStructure();
2837     VkPhysicalDeviceMaintenance4Features maintenance4Features                      = initVulkanStructure();
2838     VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5Features                   = initVulkanStructure();
2839     VkPhysicalDeviceMaintenance6FeaturesKHR maintenance6Features                   = initVulkanStructure();
2840 
2841     void **nextPtr = &features2.pNext;
2842     addToChainVulkanStructure(&nextPtr, synchronization2Features);
2843     addToChainVulkanStructure(&nextPtr, descriptorBufferFeatures);
2844     addToChainVulkanStructure(&nextPtr, bufferDeviceAddressFeatures);
2845     addToChainVulkanStructure(&nextPtr, maintenance4Features);
2846 
2847     // NOTE: VK_AMD_shader_fragment_mask must not be enabled
2848     std::vector<const char *> extensions;
2849     extensions.push_back("VK_EXT_descriptor_buffer");
2850     extensions.push_back("VK_KHR_buffer_device_address");
2851     extensions.push_back("VK_KHR_synchronization2");
2852     extensions.push_back("VK_EXT_descriptor_indexing");
2853     extensions.push_back("VK_KHR_maintenance4");
2854 
2855     if (m_params.useMaintenance5)
2856     {
2857         addToChainVulkanStructure(&nextPtr, maintenance5Features);
2858         extensions.push_back("VK_KHR_maintenance5");
2859     }
2860 
2861     if ((m_params.descriptor == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ||
2862         (m_params.variant == TestVariant::MULTIPLE) || m_params.isPushDescriptorTest())
2863     {
2864         extensions.push_back("VK_EXT_inline_uniform_block");
2865         addToChainVulkanStructure(&nextPtr, inlineUniformBlockFeatures);
2866 
2867         if (m_params.isPushDescriptorTest())
2868             extensions.push_back("VK_KHR_push_descriptor");
2869     }
2870     else if (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR ||
2871              m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS)
2872     {
2873         if (context.isDeviceFunctionalitySupported("VK_EXT_robustness2"))
2874         {
2875             extensions.push_back("VK_EXT_robustness2");
2876             addToChainVulkanStructure(&nextPtr, robustness2Features);
2877         }
2878     }
2879     else if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
2880     {
2881         extensions.push_back("VK_EXT_custom_border_color");
2882         addToChainVulkanStructure(&nextPtr, customBorderColorFeatures);
2883     }
2884     else if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
2885     {
2886         extensions.push_back("VK_EXT_mutable_descriptor_type");
2887         addToChainVulkanStructure(&nextPtr, mutableDescTypeFeatures);
2888     }
2889     else if (m_params.variant == TestVariant::YCBCR_SAMPLER)
2890     {
2891         extensions.push_back("VK_KHR_sampler_ycbcr_conversion");
2892         addToChainVulkanStructure(&nextPtr, samplerYcbcrConvFeatures);
2893     }
2894 
2895     if (m_params.isAccelerationStructure() || m_params.isRayTracing())
2896     {
2897         extensions.push_back("VK_KHR_acceleration_structure");
2898         addToChainVulkanStructure(&nextPtr, accelerationStructureFeatures);
2899         extensions.push_back("VK_KHR_spirv_1_4");
2900         extensions.push_back("VK_KHR_deferred_host_operations");
2901 
2902         if (m_params.isAccelerationStructure())
2903         {
2904             extensions.push_back("VK_KHR_ray_query");
2905             addToChainVulkanStructure(&nextPtr, rayQueryFeatures);
2906             extensions.push_back("VK_KHR_deferred_host_operations");
2907         }
2908 
2909         if (m_params.isRayTracing())
2910         {
2911             extensions.push_back("VK_KHR_ray_tracing_pipeline");
2912             addToChainVulkanStructure(&nextPtr, rayTracingPipelineFeatures);
2913         }
2914     }
2915 
2916     if (m_params.commands2)
2917     {
2918         extensions.push_back("VK_KHR_maintenance6");
2919         addToChainVulkanStructure(&nextPtr, maintenance6Features);
2920     }
2921 
2922     context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
2923 
2924     if (m_params.variant != TestVariant::ROBUST_BUFFER_ACCESS)
2925     {
2926         features2.features.robustBufferAccess   = VK_FALSE;
2927         robustness2Features.robustBufferAccess2 = VK_FALSE;
2928         robustness2Features.robustImageAccess2  = VK_FALSE;
2929     }
2930 
2931     if (m_params.variant != TestVariant::ROBUST_NULL_DESCRIPTOR)
2932     {
2933         robustness2Features.nullDescriptor = VK_FALSE;
2934     }
2935 
2936     if (!m_params.isPushDescriptorTest())
2937     {
2938         descriptorBufferFeatures.descriptorBufferPushDescriptors = VK_FALSE;
2939     }
2940 
2941     if (!maintenance4Features.maintenance4)
2942         TCU_THROW(NotSupportedError, "Execution mode LocalSizeId is used, maintenance4 required");
2943 
2944     if (m_params.isAccelerationStructure() || m_params.isRayTracing())
2945     {
2946         if (!accelerationStructureFeatures.accelerationStructure)
2947             TCU_THROW(NotSupportedError, "Require accelerationStructureFeatures.accelerationStructure");
2948 
2949         if (m_params.isCaptureReplayDescriptor(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR))
2950         {
2951             if (!accelerationStructureFeatures.accelerationStructureCaptureReplay)
2952                 TCU_THROW(NotSupportedError,
2953                           "Require accelerationStructureFeatures.accelerationStructureCaptureReplay");
2954         }
2955 
2956         if (m_params.isAccelerationStructure())
2957         {
2958             if (!rayQueryFeatures.rayQuery)
2959                 TCU_THROW(NotSupportedError, "Require rayQueryFeatures.rayQuery");
2960         }
2961 
2962         if (m_params.isRayTracing())
2963         {
2964             if (!rayTracingPipelineFeatures.rayTracingPipeline)
2965                 TCU_THROW(NotSupportedError, "Require rayTracingPipelineFeatures.rayTracingPipeline");
2966 
2967             if (m_params.isCaptureReplayDescriptor(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR))
2968             {
2969                 if (!rayTracingPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplay)
2970                     TCU_THROW(NotSupportedError,
2971                               "Require rayTracingPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplay");
2972             }
2973         }
2974     }
2975 
2976     if (m_params.commands2)
2977     {
2978         if (!maintenance6Features.maintenance6)
2979             TCU_THROW(NotSupportedError, "maintenance6 required");
2980     }
2981 
2982     // Should be enabled by default
2983     DE_ASSERT(descriptorBufferFeatures.descriptorBuffer);
2984     DE_ASSERT(synchronization2Features.synchronization2);
2985 
2986     if (m_params.variant == TestVariant::MULTIPLE || m_params.isPushDescriptorTest())
2987     {
2988         // TODO: Currently these tests assume the feature is available and there's no easy way to make it optional.
2989         // Rather than returning NotSupported, this should be reworked if many implementations have this limitation.
2990         DE_ASSERT(inlineUniformBlockFeatures.inlineUniformBlock);
2991     }
2992     else if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
2993     {
2994         DE_ASSERT(customBorderColorFeatures.customBorderColors);
2995     }
2996     else if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
2997     {
2998         DE_ASSERT(mutableDescTypeFeatures.mutableDescriptorType);
2999     }
3000     else if (params.variant == TestVariant::YCBCR_SAMPLER)
3001     {
3002         DE_ASSERT(samplerYcbcrConvFeatures.samplerYcbcrConversion);
3003     }
3004 
3005     m_descriptorBufferFeatures       = descriptorBufferFeatures;
3006     m_descriptorBufferFeatures.pNext = nullptr;
3007 
3008     m_descriptorBufferProperties =
3009         *findStructure<VkPhysicalDeviceDescriptorBufferPropertiesEXT>(&context.getDeviceProperties2());
3010     m_descriptorBufferProperties.pNext = nullptr;
3011 
3012     VkDeviceCreateInfo createInfo      = initVulkanStructure(&features2);
3013     createInfo.pEnabledFeatures        = DE_NULL;
3014     createInfo.enabledExtensionCount   = u32(extensions.size());
3015     createInfo.ppEnabledExtensionNames = extensions.data();
3016     createInfo.queueCreateInfoCount    = 1;
3017     createInfo.pQueueCreateInfos       = &queueInfo;
3018 
3019     m_device =
3020         createCustomDevice(false, context.getPlatformInterface(), context.getInstance(), inst, physDevice, &createInfo);
3021 
3022     context.getDeviceInterface().getDeviceQueue(*m_device, m_queueFamilyIndex, 0, &m_queue);
3023 
3024     m_deviceInterface =
3025         newMovePtr<DeviceDriver>(context.getPlatformInterface(), context.getInstance(), *m_device,
3026                                  context.getUsedApiVersion(), context.getTestContext().getCommandLine());
3027 
3028     m_memoryProperties = vk::getPhysicalDeviceMemoryProperties(inst, physDevice);
3029 
3030     if (params.variant == TestVariant::YCBCR_SAMPLER)
3031     {
3032         m_imageColorFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
3033 
3034         VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = initVulkanStructure();
3035         imageFormatInfo.format                           = m_imageColorFormat;
3036         imageFormatInfo.type                             = VK_IMAGE_TYPE_2D;
3037         imageFormatInfo.tiling                           = VK_IMAGE_TILING_OPTIMAL;
3038         imageFormatInfo.usage                            = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
3039 
3040         VkSamplerYcbcrConversionImageFormatProperties ycbcrFormatProps = initVulkanStructure();
3041         VkImageFormatProperties2 imageFormatProps                      = initVulkanStructure(&ycbcrFormatProps);
3042 
3043         VK_CHECK(m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(
3044             m_context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProps));
3045 
3046         m_combinedImageSamplerDescriptorCount = ycbcrFormatProps.combinedImageSamplerDescriptorCount;
3047 
3048         DE_ASSERT(m_combinedImageSamplerDescriptorCount != 0);
3049     }
3050     else
3051     {
3052         m_imageColorFormat = VK_FORMAT_R32_UINT;
3053     }
3054 
3055     m_allocatorPtr = de::MovePtr<Allocator>(new SimpleAllocator(*m_deviceInterface, *m_device, m_memoryProperties));
3056 }
3057 
getDescriptorSize(const Binding & binding) const3058 VkDeviceSize DescriptorBufferTestInstance::getDescriptorSize(const Binding &binding) const
3059 {
3060     const auto isRobustBufferAccess = (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS);
3061 
3062     // To support mutable descriptor type bindings, we pick the max size from the list below.
3063     // For regular descriptors, there will be only one element in the list.
3064     std::vector<VkDescriptorType> typeList;
3065 
3066     if (binding.isMutableType)
3067     {
3068         DE_ASSERT(m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE);
3069         typeList = getDescriptorMaskTypes(m_params.mutableDescriptorTypes);
3070     }
3071     else
3072     {
3073         typeList.emplace_back(binding.descriptorType);
3074     }
3075 
3076     std::size_t maxSize = 0u;
3077 
3078     for (const auto &type : typeList)
3079     {
3080         std::size_t size = 0u;
3081 
3082         switch (type)
3083         {
3084         case VK_DESCRIPTOR_TYPE_SAMPLER:
3085             size = m_descriptorBufferProperties.samplerDescriptorSize;
3086             break;
3087 
3088         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3089             size =
3090                 m_descriptorBufferProperties.combinedImageSamplerDescriptorSize * m_combinedImageSamplerDescriptorCount;
3091             break;
3092 
3093         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3094             size = m_descriptorBufferProperties.sampledImageDescriptorSize;
3095             break;
3096 
3097         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
3098             size = m_descriptorBufferProperties.storageImageDescriptorSize;
3099             break;
3100 
3101         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3102             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformTexelBufferDescriptorSize :
3103                                           m_descriptorBufferProperties.uniformTexelBufferDescriptorSize;
3104             break;
3105 
3106         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
3107             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageTexelBufferDescriptorSize :
3108                                           m_descriptorBufferProperties.storageTexelBufferDescriptorSize;
3109             break;
3110 
3111         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3112             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformBufferDescriptorSize :
3113                                           m_descriptorBufferProperties.uniformBufferDescriptorSize;
3114             break;
3115 
3116         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3117             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageBufferDescriptorSize :
3118                                           m_descriptorBufferProperties.storageBufferDescriptorSize;
3119             break;
3120 
3121         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
3122             size = m_descriptorBufferProperties.inputAttachmentDescriptorSize;
3123             break;
3124 
3125         case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
3126             size = m_descriptorBufferProperties.accelerationStructureDescriptorSize;
3127             break;
3128 
3129         case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
3130             // Inline uniform block has no associated size. This is OK, because it can't be arrayed.
3131             break;
3132 
3133         default:
3134             DE_ASSERT(0);
3135             break;
3136         }
3137 
3138         maxSize = std::max(maxSize, size);
3139     }
3140 
3141     return maxSize;
3142 }
3143 
getDescriptorTypeSize(VkDescriptorType descriptorType) const3144 VkDeviceSize DescriptorBufferTestInstance::getDescriptorTypeSize(VkDescriptorType descriptorType) const
3145 {
3146     const auto isRobustBufferAccess = (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS);
3147 
3148     switch (descriptorType)
3149     {
3150     case VK_DESCRIPTOR_TYPE_SAMPLER:
3151         return m_descriptorBufferProperties.samplerDescriptorSize;
3152 
3153     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3154         return m_descriptorBufferProperties.combinedImageSamplerDescriptorSize * m_combinedImageSamplerDescriptorCount;
3155 
3156     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3157         return m_descriptorBufferProperties.sampledImageDescriptorSize;
3158 
3159     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
3160         return m_descriptorBufferProperties.storageImageDescriptorSize;
3161 
3162     case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3163         return isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformTexelBufferDescriptorSize :
3164                                       m_descriptorBufferProperties.uniformTexelBufferDescriptorSize;
3165 
3166     case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
3167         return isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageTexelBufferDescriptorSize :
3168                                       m_descriptorBufferProperties.storageTexelBufferDescriptorSize;
3169 
3170     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3171         return isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformBufferDescriptorSize :
3172                                       m_descriptorBufferProperties.uniformBufferDescriptorSize;
3173 
3174     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3175         return isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageBufferDescriptorSize :
3176                                       m_descriptorBufferProperties.storageBufferDescriptorSize;
3177 
3178     case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
3179         return m_descriptorBufferProperties.inputAttachmentDescriptorSize;
3180 
3181     case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
3182         return m_descriptorBufferProperties.accelerationStructureDescriptorSize;
3183 
3184     case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
3185         // Inline uniform block has no associated size. This is OK, because it can't be arrayed.
3186         break;
3187 
3188     default:
3189         DE_ASSERT(0);
3190         break;
3191     }
3192 
3193     return 0;
3194 }
3195 
createDescriptorSetLayouts()3196 void DescriptorBufferTestInstance::createDescriptorSetLayouts()
3197 {
3198     for (auto &dslPtr : m_descriptorSetLayouts)
3199     {
3200         auto &dsl = **dslPtr;
3201 
3202         DE_ASSERT(!dsl.bindings.empty());
3203 
3204         const auto bindingsCopy = getDescriptorSetLayoutBindings(dsl.bindings);
3205 
3206         VkMutableDescriptorTypeCreateInfoEXT mutableDescTypeCreateInfo = initVulkanStructure();
3207         std::vector<VkMutableDescriptorTypeListEXT> mutableDescTypeLists;
3208         std::vector<VkDescriptorType> mutableDescTypeDescriptors;
3209 
3210         VkDescriptorSetLayoutCreateInfo createInfo = initVulkanStructure();
3211         createInfo.bindingCount                    = u32(bindingsCopy.size());
3212         createInfo.pBindings                       = bindingsCopy.data();
3213         createInfo.flags                           = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
3214 
3215         if (dsl.hasEmbeddedImmutableSamplers)
3216         {
3217             createInfo.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT;
3218         }
3219         else if (dsl.usePushDescriptors)
3220         {
3221             createInfo.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
3222         }
3223 
3224         if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
3225         {
3226             // Prepare mutable descriptor type structures
3227 
3228             // NOTE: This test makes a simplification that each mutable descriptor binding has the same
3229             //       set of possible real descriptor types. Due to this, we can use a single descriptor type list.
3230             mutableDescTypeDescriptors = getDescriptorMaskTypes(m_params.mutableDescriptorTypes);
3231             mutableDescTypeLists.resize(createInfo.bindingCount);
3232 
3233             createInfo.pNext                                         = &mutableDescTypeCreateInfo;
3234             mutableDescTypeCreateInfo.mutableDescriptorTypeListCount = u32(mutableDescTypeLists.size());
3235             mutableDescTypeCreateInfo.pMutableDescriptorTypeLists    = mutableDescTypeLists.data();
3236 
3237             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
3238             {
3239                 const auto &binding = dsl.bindings[bindingIndex];
3240 
3241                 if (binding.isMutableType)
3242                 {
3243                     DE_ASSERT(binding.immutableSamplers[0] == DE_NULL);
3244                     mutableDescTypeLists[bindingIndex].descriptorTypeCount = u32(mutableDescTypeDescriptors.size());
3245                     mutableDescTypeLists[bindingIndex].pDescriptorTypes    = mutableDescTypeDescriptors.data();
3246                 }
3247                 else
3248                 {
3249                     mutableDescTypeLists[bindingIndex].descriptorTypeCount = 0;
3250                     mutableDescTypeLists[bindingIndex].pDescriptorTypes    = nullptr;
3251                 }
3252             }
3253 
3254             // Check support
3255 
3256             VkDescriptorSetLayoutSupport support = initVulkanStructure();
3257 
3258             m_deviceInterface->getDescriptorSetLayoutSupport(*m_device, &createInfo, &support);
3259 
3260             if (support.supported == VK_FALSE)
3261             {
3262                 TCU_THROW(NotSupportedError, "Descriptor set layout is not supported");
3263             }
3264         }
3265 
3266         dsl.layout = createDescriptorSetLayout(*m_deviceInterface, *m_device, &createInfo);
3267 
3268         m_deviceInterface->getDescriptorSetLayoutSizeEXT(*m_device, *dsl.layout, &dsl.sizeOfLayout);
3269 
3270         for (auto &binding : dsl.bindings)
3271         {
3272             m_deviceInterface->getDescriptorSetLayoutBindingOffsetEXT(*m_device, *dsl.layout, binding.binding,
3273                                                                       &binding.offset);
3274         }
3275     }
3276 }
3277 
3278 // The test may create a variable number of descriptor buffers, based on the parameters.
3279 //
createDescriptorBuffers()3280 void DescriptorBufferTestInstance::createDescriptorBuffers()
3281 {
3282     DE_ASSERT(m_descriptorBuffers.empty());
3283 
3284     const uint8_t bufferInitialMemory             = 0xcc;  // descriptor buffer memory is initially set to this
3285     bool allocateStagingBuffer                    = false; // determined after descriptors are created
3286     VkDeviceSize stagingBufferDescriptorSetOffset = 0;
3287     const uint32_t setsPerBuffer =
3288         m_params.subcase == SubCase::SINGLE_BUFFER ? m_params.bufferBindingCount + 1 : m_params.setsPerBuffer;
3289 
3290     // Data tracked per buffer creation
3291     struct
3292     {
3293         uint32_t firstSet;
3294         uint32_t numSets;
3295         VkBufferUsageFlags usage;
3296         VkDeviceSize setOffset;
3297     } currentBuffer;
3298 
3299     currentBuffer = {};
3300 
3301     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3302     {
3303         auto &dsl = **m_descriptorSetLayouts[setIndex];
3304 
3305         if (dsl.hasEmbeddedImmutableSamplers ||
3306             (dsl.usePushDescriptors && m_descriptorBufferProperties.bufferlessPushDescriptors &&
3307              m_params.subcase != SubCase::SINGLE_BUFFER))
3308         {
3309             // Embedded immutable samplers aren't backed by a descriptor buffer.
3310             // Same goes for the set used with push descriptors.
3311             // Push descriptors might require buffer. If so, don't skip creation of buffer.
3312 
3313             // We musn't have started adding sets to the next buffer yet.
3314             DE_ASSERT(currentBuffer.numSets == 0);
3315             ++currentBuffer.firstSet;
3316 
3317             continue;
3318         }
3319 
3320         // Required for binding
3321         currentBuffer.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
3322 
3323         for (const auto &binding : dsl.bindings)
3324         {
3325             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
3326             {
3327                 currentBuffer.usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT;
3328             }
3329             else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
3330             {
3331                 currentBuffer.usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT |
3332                                        VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;
3333             }
3334             else
3335             {
3336                 currentBuffer.usage |= VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;
3337             }
3338         }
3339 
3340         if (!m_descriptorBufferProperties.bufferlessPushDescriptors && dsl.usePushDescriptors)
3341         {
3342             currentBuffer.usage |= VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT;
3343         }
3344 
3345         // Allow descriptor set layout to be size of zero bytes
3346         if (dsl.sizeOfLayout != 0)
3347         {
3348             // Assign this descriptor set to a new buffer
3349             dsl.bufferIndex  = u32(m_descriptorBuffers.size());
3350             dsl.bufferOffset = currentBuffer.setOffset;
3351         }
3352 
3353         currentBuffer.numSets += 1;
3354         currentBuffer.setOffset +=
3355             deAlignSize(static_cast<std::size_t>(dsl.sizeOfLayout),
3356                         static_cast<std::size_t>(m_descriptorBufferProperties.descriptorBufferOffsetAlignment));
3357 
3358         VkMemoryAllocateFlagsInfo allocFlagsInfo = initVulkanStructure();
3359         allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
3360 
3361         // We've reached the limit of sets for this descriptor buffer.
3362         if (currentBuffer.numSets == setsPerBuffer)
3363         {
3364             vk::VkBufferCreateInfo bufferCreateInfo =
3365                 makeBufferCreateInfo(currentBuffer.setOffset, currentBuffer.usage);
3366 
3367             if (bufferCreateInfo.size != 0)
3368             {
3369                 m_descriptorBuffers.emplace_back(new BufferAlloc());
3370                 auto &bufferAlloc = *m_descriptorBuffers.back();
3371 
3372                 bufferAlloc.size  = bufferCreateInfo.size;
3373                 bufferAlloc.usage = bufferCreateInfo.usage;
3374 
3375                 vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = initVulkanStructure();
3376                 ;
3377                 if (m_params.useMaintenance5)
3378                 {
3379                     bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)currentBuffer.usage;
3380                     bufferCreateInfo.pNext  = &bufferUsageFlags2;
3381                     bufferCreateInfo.usage  = 0;
3382                 }
3383 
3384                 bufferAlloc.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3385 
3386                 auto bufferMemReqs   = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferAlloc.buffer);
3387                 bool useStagedUpload = false; // write directly to device-local memory, if possible
3388 
3389                 if (DEBUG_FORCE_STAGED_UPLOAD)
3390                 {
3391                     useStagedUpload = true;
3392                 }
3393                 else if (DEBUG_MIX_DIRECT_AND_STAGED_UPLOAD)
3394                 {
3395                     // To avoid adding yet another test case permutation (which may be redundant on some implementations),
3396                     // we are going to always test a mix of direct and staged uploads.
3397                     useStagedUpload = ((dsl.bufferIndex % 2) == 1);
3398                 }
3399 
3400                 if (!useStagedUpload)
3401                 {
3402                     auto memReqs = MemoryRequirement::Local | MemoryRequirement::HostVisible;
3403                     auto compatMask =
3404                         bufferMemReqs.memoryTypeBits & getCompatibleMemoryTypes(m_memoryProperties, memReqs);
3405 
3406                     if (compatMask != 0)
3407                     {
3408                         bufferAlloc.alloc = allocate(bufferMemReqs, memReqs, &allocFlagsInfo);
3409                     }
3410                     else
3411                     {
3412                         // No suitable memory type, fall back to a staged upload
3413                         useStagedUpload = true;
3414                     }
3415                 }
3416 
3417                 if (useStagedUpload)
3418                 {
3419                     DE_ASSERT(!bufferAlloc.alloc);
3420 
3421                     if ((bufferAlloc.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) == 0)
3422                     {
3423                         bufferAlloc.buffer = Move<VkBuffer>();
3424                         bufferAlloc.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
3425 
3426                         bufferCreateInfo.usage = bufferAlloc.usage;
3427 
3428                         bufferAlloc.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3429 
3430                         bufferMemReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferAlloc.buffer);
3431                     }
3432 
3433                     bufferAlloc.alloc     = allocate(bufferMemReqs, MemoryRequirement::Local, &allocFlagsInfo);
3434                     allocateStagingBuffer = true;
3435 
3436                     // Update staging buffer offsets for all sets in this buffer
3437                     for (uint32_t i = currentBuffer.firstSet; i < currentBuffer.firstSet + currentBuffer.numSets; ++i)
3438                     {
3439                         (**m_descriptorSetLayouts[i]).stagingBufferOffset = stagingBufferDescriptorSetOffset;
3440                         stagingBufferDescriptorSetOffset += (**m_descriptorSetLayouts[i]).sizeOfLayout;
3441                     }
3442                 }
3443 
3444                 VK_CHECK(m_deviceInterface->bindBufferMemory(
3445                     *m_device, *bufferAlloc.buffer, bufferAlloc.alloc->getMemory(), bufferAlloc.alloc->getOffset()));
3446 
3447                 bufferAlloc.loadDeviceAddress(*m_deviceInterface, *m_device);
3448 
3449                 if (!useStagedUpload)
3450                 {
3451                     // Clear the descriptor buffer memory to ensure there can be no random data there.
3452                     deMemset(bufferAlloc.alloc->getHostPtr(), bufferInitialMemory,
3453                              static_cast<std::size_t>(bufferAlloc.size));
3454                 }
3455             }
3456 
3457             // Start with a new buffer
3458             currentBuffer          = {};
3459             currentBuffer.firstSet = setIndex + 1;
3460         }
3461     }
3462 
3463     if (allocateStagingBuffer)
3464     {
3465         DE_ASSERT(!m_descriptorStagingBuffer.alloc);
3466 
3467         auto bufferCreateInfo =
3468             makeBufferCreateInfo(stagingBufferDescriptorSetOffset, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
3469 
3470         m_descriptorStagingBuffer.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3471         m_descriptorStagingBuffer.size   = bufferCreateInfo.size;
3472 
3473         auto bufferMemReqs =
3474             getBufferMemoryRequirements(*m_deviceInterface, *m_device, *m_descriptorStagingBuffer.buffer);
3475 
3476         m_descriptorStagingBuffer.alloc = allocate(bufferMemReqs, MemoryRequirement::HostVisible);
3477 
3478         VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *m_descriptorStagingBuffer.buffer,
3479                                                      m_descriptorStagingBuffer.alloc->getMemory(),
3480                                                      m_descriptorStagingBuffer.alloc->getOffset()));
3481 
3482         // Clear the descriptor buffer memory to ensure there can be no random data there.
3483         deMemset(m_descriptorStagingBuffer.alloc->getHostPtr(), bufferInitialMemory,
3484                  static_cast<std::size_t>(m_descriptorStagingBuffer.size));
3485     }
3486 }
3487 
bindDescriptorBuffers(VkCommandBuffer cmdBuf,VkPipelineBindPoint bindPoint) const3488 void DescriptorBufferTestInstance::bindDescriptorBuffers(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint) const
3489 {
3490     std::vector<uint32_t> bufferIndices;
3491     std::vector<VkDeviceSize> bufferOffsets;
3492     std::vector<VkDescriptorBufferBindingInfoEXT> bufferBindingInfos;
3493     VkDescriptorBufferBindingPushDescriptorBufferHandleEXT bufferBindingPushDescriptorBufferHandleEXT =
3494         initVulkanStructure();
3495 
3496     uint32_t firstSet = 0;
3497 
3498     if (m_params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
3499     {
3500         // These sampler sets are ordered first, so we can bind them now and increment the firstSet index.
3501         for (uint32_t setIndex = firstSet; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3502         {
3503             const auto &dsl = **m_descriptorSetLayouts[setIndex];
3504 
3505             if (dsl.hasEmbeddedImmutableSamplers)
3506             {
3507                 if (m_params.commands2)
3508                 {
3509                     vk::VkBindDescriptorBufferEmbeddedSamplersInfoEXT bindDescriptorBufferEmbeddedSamplersInfo = {
3510                         VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT, // VkStructureType sType;
3511                         DE_NULL,                                                             // const void* pNext;
3512                         (VkShaderStageFlags)m_params.stage, // VkShaderStageFlags stageFlags;
3513                         *m_pipelineLayout,                  // VkPipelineLayout layout;
3514                         setIndex                            // uint32_t set;
3515                     };
3516                     m_deviceInterface->cmdBindDescriptorBufferEmbeddedSamplers2EXT(
3517                         cmdBuf, &bindDescriptorBufferEmbeddedSamplersInfo);
3518                 }
3519                 else
3520                 {
3521                     m_deviceInterface->cmdBindDescriptorBufferEmbeddedSamplersEXT(cmdBuf, bindPoint, *m_pipelineLayout,
3522                                                                                   setIndex);
3523                 }
3524 
3525                 // No gaps between sets.
3526                 DE_ASSERT(firstSet == setIndex);
3527 
3528                 firstSet = setIndex + 1;
3529             }
3530         }
3531     }
3532 
3533     for (const auto &buffer : m_descriptorBuffers)
3534     {
3535         VkDescriptorBufferBindingInfoEXT info = initVulkanStructure();
3536 
3537         info.address = buffer->deviceAddress;
3538         info.usage   = buffer->usage;
3539 
3540         if (!m_descriptorBufferProperties.bufferlessPushDescriptors &&
3541             (buffer->usage & VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT) != 0)
3542         {
3543             info.pNext = &bufferBindingPushDescriptorBufferHandleEXT;
3544 
3545             // Make sure there is only one such buffer
3546             DE_ASSERT(bufferBindingPushDescriptorBufferHandleEXT.buffer == DE_NULL);
3547 
3548             bufferBindingPushDescriptorBufferHandleEXT.buffer = *buffer->buffer;
3549 
3550             DE_ASSERT(bufferBindingPushDescriptorBufferHandleEXT.buffer != DE_NULL);
3551         }
3552 
3553         bufferBindingInfos.emplace_back(info);
3554     }
3555 
3556     if (bufferBindingInfos.size() != 0u)
3557     {
3558         m_deviceInterface->cmdBindDescriptorBuffersEXT(cmdBuf, u32(bufferBindingInfos.size()),
3559                                                        bufferBindingInfos.data());
3560     }
3561 
3562     // Next, set the offsets for the bound buffers.
3563 
3564     for (uint32_t setIndex = firstSet; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3565     {
3566         const auto &dsl       = **m_descriptorSetLayouts[setIndex];
3567         const bool isBoundSet = (dsl.bufferIndex != INDEX_INVALID);
3568         const bool isLastSet  = ((setIndex + 1) == u32(m_descriptorSetLayouts.size()));
3569 
3570         if (isBoundSet)
3571         {
3572             bufferIndices.emplace_back(dsl.bufferIndex);
3573             bufferOffsets.emplace_back(dsl.bufferOffset);
3574         }
3575 
3576         if ((!isBoundSet || isLastSet) && !bufferIndices.empty())
3577         {
3578             if (m_params.commands2)
3579             {
3580                 vk::VkSetDescriptorBufferOffsetsInfoEXT setDescriptorBufferOffsetInfo = {
3581                     VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT, // VkStructureType sType;
3582                     DE_NULL,                                                  // const void* pNext;
3583                     (VkShaderStageFlags)m_params.stage,                       // VkShaderStageFlags stageFlags;
3584                     *m_pipelineLayout,                                        // VkPipelineLayout layout;
3585                     firstSet,                                                 // uint32_t firstSet;
3586                     u32(bufferIndices.size()),                                // uint32_t setCount;
3587                     bufferIndices.data(),                                     // const uint32_t* pBufferIndices;
3588                     bufferOffsets.data()                                      // const VkDeviceSize* pOffsets;
3589                 };
3590                 m_deviceInterface->cmdSetDescriptorBufferOffsets2EXT(cmdBuf, &setDescriptorBufferOffsetInfo);
3591             }
3592             else
3593             {
3594                 m_deviceInterface->cmdSetDescriptorBufferOffsetsEXT(cmdBuf, bindPoint, *m_pipelineLayout, firstSet,
3595                                                                     u32(bufferIndices.size()), bufferIndices.data(),
3596                                                                     bufferOffsets.data());
3597             }
3598 
3599             bufferIndices.clear();
3600             bufferOffsets.clear();
3601 
3602             firstSet = setIndex + 1;
3603         }
3604         else if (!isBoundSet)
3605         {
3606             // Push descriptor sets will have no buffer backing. Skip this set.
3607             ++firstSet;
3608         }
3609     }
3610 }
3611 
makeShaderStageCreateInfo(VkShaderStageFlagBits stage,VkShaderModule shaderModule)3612 VkPipelineShaderStageCreateInfo makeShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule shaderModule)
3613 {
3614     VkPipelineShaderStageCreateInfo createInfo = initVulkanStructure();
3615     createInfo.stage                           = stage;
3616     createInfo.module                          = shaderModule;
3617     createInfo.pName                           = "main";
3618     createInfo.pSpecializationInfo             = nullptr;
3619     return createInfo;
3620 }
3621 
createShaderBindingTable(const InstanceInterface & vki,const DeviceInterface & vkd,const VkDevice device,const VkPhysicalDevice physicalDevice,const VkPipeline pipeline,Allocator & allocator,de::MovePtr<RayTracingPipeline> & rayTracingPipeline,const uint32_t group)3622 de::MovePtr<BufferWithMemory> DescriptorBufferTestInstance::createShaderBindingTable(
3623     const InstanceInterface &vki, const DeviceInterface &vkd, const VkDevice device,
3624     const VkPhysicalDevice physicalDevice, const VkPipeline pipeline, Allocator &allocator,
3625     de::MovePtr<RayTracingPipeline> &rayTracingPipeline, const uint32_t group)
3626 {
3627     de::MovePtr<BufferWithMemory> shaderBindingTable;
3628 
3629     if (group < m_shaderGroupCount)
3630     {
3631         const uint32_t shaderGroupHandleSize    = getShaderGroupHandleSize(vki, physicalDevice);
3632         const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
3633 
3634         shaderBindingTable = rayTracingPipeline->createShaderBindingTable(
3635             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, group, 1u);
3636     }
3637 
3638     return shaderBindingTable;
3639 }
3640 
createRayTracingPipeline()3641 void DescriptorBufferTestInstance::createRayTracingPipeline()
3642 {
3643     const InstanceInterface &vki          = m_context.getInstanceInterface();
3644     const DeviceInterface &vkd            = *m_deviceInterface;
3645     const VkDevice device                 = *m_device;
3646     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
3647     vk::BinaryCollection &collection      = m_context.getBinaryCollection();
3648     Allocator &allocator                  = *m_allocatorPtr;
3649     const uint32_t shaderGroupHandleSize  = getShaderGroupHandleSize(vki, physicalDevice);
3650     const VkShaderStageFlags hitStages =
3651         VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
3652 
3653     m_shaderGroupCount = 0;
3654 
3655     if (collection.contains(getShaderName(VK_SHADER_STAGE_RAYGEN_BIT_KHR)))
3656         m_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;
3657     if (collection.contains(getShaderName(VK_SHADER_STAGE_ANY_HIT_BIT_KHR)))
3658         m_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
3659     if (collection.contains(getShaderName(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)))
3660         m_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
3661     if (collection.contains(getShaderName(VK_SHADER_STAGE_MISS_BIT_KHR)))
3662         m_shaders |= VK_SHADER_STAGE_MISS_BIT_KHR;
3663     if (collection.contains(getShaderName(VK_SHADER_STAGE_INTERSECTION_BIT_KHR)))
3664         m_shaders |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
3665     if (collection.contains(getShaderName(VK_SHADER_STAGE_CALLABLE_BIT_KHR)))
3666         m_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;
3667 
3668     if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
3669         m_raygenShaderGroup = m_shaderGroupCount++;
3670 
3671     if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
3672         m_missShaderGroup = m_shaderGroupCount++;
3673 
3674     if (0 != (m_shaders & hitStages))
3675         m_hitShaderGroup = m_shaderGroupCount++;
3676 
3677     if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR))
3678         m_callableShaderGroup = m_shaderGroupCount++;
3679 
3680     m_rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
3681 
3682     m_rayTracingPipeline->setCreateFlags(VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT);
3683 
3684     if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
3685         addRayTracingShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, m_raygenShaderGroup);
3686     if (0 != (m_shaders & VK_SHADER_STAGE_ANY_HIT_BIT_KHR))
3687         addRayTracingShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, m_hitShaderGroup);
3688     if (0 != (m_shaders & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR))
3689         addRayTracingShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, m_hitShaderGroup);
3690     if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
3691         addRayTracingShader(VK_SHADER_STAGE_MISS_BIT_KHR, m_missShaderGroup);
3692     if (0 != (m_shaders & VK_SHADER_STAGE_INTERSECTION_BIT_KHR))
3693         addRayTracingShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, m_hitShaderGroup);
3694     if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR))
3695         addRayTracingShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, m_callableShaderGroup);
3696 
3697     m_pipelineLayout = makePipelineLayout(vkd, device, getDescriptorSetLayouts(m_descriptorSetLayouts));
3698     m_pipeline       = m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
3699 
3700     m_raygenShaderBindingTable   = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3701                                                             m_rayTracingPipeline, m_raygenShaderGroup);
3702     m_missShaderBindingTable     = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3703                                                             m_rayTracingPipeline, m_missShaderGroup);
3704     m_hitShaderBindingTable      = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3705                                                             m_rayTracingPipeline, m_hitShaderGroup);
3706     m_callableShaderBindingTable = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3707                                                             m_rayTracingPipeline, m_callableShaderGroup);
3708 
3709     m_raygenShaderBindingTableRegion =
3710         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_raygenShaderBindingTable), shaderGroupHandleSize);
3711     m_missShaderBindingTableRegion =
3712         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_missShaderBindingTable), shaderGroupHandleSize);
3713     m_hitShaderBindingTableRegion =
3714         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_hitShaderBindingTable), shaderGroupHandleSize);
3715     m_callableShaderBindingTableRegion =
3716         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_callableShaderBindingTable), shaderGroupHandleSize);
3717 }
3718 
addRayTracingShader(const VkShaderStageFlagBits stage,const uint32_t group)3719 void DescriptorBufferTestInstance::addRayTracingShader(const VkShaderStageFlagBits stage, const uint32_t group)
3720 {
3721     DE_ASSERT(m_rayTracingPipeline != DE_NULL);
3722 
3723     m_rayTracingPipeline->addShader(stage, createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(stage), 0),
3724                                     group);
3725 }
3726 
3727 // The graphics pipeline is very simple for this test.
3728 // The number of shader stages is configurable. There's no vertex input, a single triangle covers the entire viewport.
3729 // The color target uses R32_UINT format and is used to save the verifcation result.
3730 //
createGraphicsPipeline()3731 void DescriptorBufferTestInstance::createGraphicsPipeline()
3732 {
3733     std::vector<VkImageView> framebufferAttachments;
3734 
3735     {
3736         m_colorImage.info                       = initVulkanStructure();
3737         m_colorImage.info.flags                 = 0;
3738         m_colorImage.info.imageType             = VK_IMAGE_TYPE_2D;
3739         m_colorImage.info.format                = VK_FORMAT_R32_UINT;
3740         m_colorImage.info.extent.width          = m_renderArea.extent.width;
3741         m_colorImage.info.extent.height         = m_renderArea.extent.height;
3742         m_colorImage.info.extent.depth          = 1;
3743         m_colorImage.info.mipLevels             = 1;
3744         m_colorImage.info.arrayLayers           = 1;
3745         m_colorImage.info.samples               = VK_SAMPLE_COUNT_1_BIT;
3746         m_colorImage.info.tiling                = VK_IMAGE_TILING_OPTIMAL;
3747         m_colorImage.info.usage                 = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3748         m_colorImage.info.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3749         m_colorImage.info.queueFamilyIndexCount = 0;
3750         m_colorImage.info.pQueueFamilyIndices   = nullptr;
3751         m_colorImage.info.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
3752 
3753         m_colorImage.image = createImage(*m_deviceInterface, *m_device, &m_colorImage.info);
3754 
3755         auto memReqs           = getImageMemoryRequirements(*m_deviceInterface, *m_device, *m_colorImage.image);
3756         m_colorImage.sizeBytes = memReqs.size;
3757         m_colorImage.alloc     = allocate(memReqs, MemoryRequirement::Local);
3758 
3759         VK_CHECK(m_deviceInterface->bindImageMemory(*m_device, *m_colorImage.image, m_colorImage.alloc->getMemory(),
3760                                                     m_colorImage.alloc->getOffset()));
3761     }
3762     {
3763         auto createInfo = makeBufferCreateInfo(m_colorImage.sizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
3764 
3765         m_colorBuffer.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3766 
3767         auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *m_colorBuffer.buffer);
3768 
3769         m_colorBuffer.alloc = allocate(memReqs, MemoryRequirement::HostVisible);
3770         VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *m_colorBuffer.buffer, m_colorBuffer.alloc->getMemory(),
3771                                                      m_colorBuffer.alloc->getOffset()));
3772     }
3773     {
3774         VkImageViewCreateInfo createInfo = initVulkanStructure();
3775         createInfo.image                 = *m_colorImage.image;
3776         createInfo.viewType              = VK_IMAGE_VIEW_TYPE_2D;
3777         createInfo.format                = m_colorImage.info.format;
3778         createInfo.components            = ComponentMappingIdentity;
3779         createInfo.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
3780 
3781         m_colorImage.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
3782     }
3783 
3784     framebufferAttachments.push_back(*m_colorImage.imageView);
3785 
3786     {
3787         std::vector<VkAttachmentDescription> attachments;
3788         std::vector<VkAttachmentReference> colorRefs;
3789         std::vector<VkAttachmentReference> inputRefs;
3790 
3791         {
3792             VkAttachmentDescription colorAttachment{};
3793             colorAttachment.format         = VK_FORMAT_R32_UINT;
3794             colorAttachment.samples        = VK_SAMPLE_COUNT_1_BIT;
3795             colorAttachment.loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
3796             colorAttachment.storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
3797             colorAttachment.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3798             colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3799             colorAttachment.initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
3800             colorAttachment.finalLayout    = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3801 
3802             colorRefs.emplace_back(
3803                 makeAttachmentReference(u32(attachments.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
3804             attachments.emplace_back(colorAttachment);
3805         }
3806 
3807         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3808         {
3809             const auto &dsl = **m_descriptorSetLayouts[setIndex];
3810 
3811             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
3812             {
3813                 const auto &binding = dsl.bindings[bindingIndex];
3814 
3815                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
3816                 {
3817                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
3818                     {
3819                         VkAttachmentDescription inputAttachment{};
3820                         inputAttachment.format         = m_imageColorFormat;
3821                         inputAttachment.samples        = VK_SAMPLE_COUNT_1_BIT;
3822                         inputAttachment.loadOp         = VK_ATTACHMENT_LOAD_OP_LOAD;
3823                         inputAttachment.storeOp        = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3824                         inputAttachment.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3825                         inputAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3826                         inputAttachment.initialLayout  = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3827                         inputAttachment.finalLayout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3828 
3829                         inputRefs.emplace_back(
3830                             makeAttachmentReference(u32(attachments.size()), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
3831                         attachments.emplace_back(inputAttachment);
3832 
3833                         const auto inputAttachmentResourceIndex = binding.perBindingResourceIndex[arrayIndex];
3834                         framebufferAttachments.push_back(
3835                             *(**m_resources[inputAttachmentResourceIndex]).image.imageView);
3836                     }
3837                 }
3838             }
3839         }
3840 
3841         VkSubpassDescription subpass{};
3842         subpass.pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
3843         subpass.inputAttachmentCount    = u32(inputRefs.size());
3844         subpass.pInputAttachments       = inputRefs.data();
3845         subpass.colorAttachmentCount    = u32(colorRefs.size());
3846         subpass.pColorAttachments       = colorRefs.data();
3847         subpass.pResolveAttachments     = nullptr;
3848         subpass.pDepthStencilAttachment = nullptr;
3849         subpass.preserveAttachmentCount = 0;
3850         subpass.pPreserveAttachments    = nullptr;
3851 
3852         VkRenderPassCreateInfo createInfo = initVulkanStructure();
3853         // No explicit dependencies
3854         createInfo.attachmentCount = u32(attachments.size());
3855         createInfo.pAttachments    = attachments.data();
3856         createInfo.subpassCount    = 1;
3857         createInfo.pSubpasses      = &subpass;
3858 
3859         m_renderPass = createRenderPass(*m_deviceInterface, *m_device, &createInfo);
3860     }
3861     {
3862         VkFramebufferCreateInfo createInfo = initVulkanStructure();
3863         createInfo.renderPass              = *m_renderPass;
3864         createInfo.attachmentCount         = u32(framebufferAttachments.size());
3865         createInfo.pAttachments            = framebufferAttachments.data();
3866         createInfo.width                   = m_renderArea.extent.width;
3867         createInfo.height                  = m_renderArea.extent.height;
3868         createInfo.layers                  = 1;
3869 
3870         m_framebuffer = createFramebuffer(*m_deviceInterface, *m_device, &createInfo);
3871     }
3872 
3873     std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
3874 
3875     Move<VkShaderModule> vertModule;
3876     Move<VkShaderModule> tessControlModule;
3877     Move<VkShaderModule> tessEvalModule;
3878     Move<VkShaderModule> geomModule;
3879     Move<VkShaderModule> fragModule;
3880 
3881     vertModule = createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_VERTEX_BIT), 0u);
3882     fragModule = createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_FRAGMENT_BIT), 0u);
3883 
3884     shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, *vertModule));
3885     shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, *fragModule));
3886 
3887     if (m_params.isTessellation())
3888     {
3889         tessControlModule = createShaderModule(*m_deviceInterface, *m_device,
3890                                                getShaderBinary(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), 0u);
3891         tessEvalModule    = createShaderModule(*m_deviceInterface, *m_device,
3892                                                getShaderBinary(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), 0u);
3893 
3894         shaderStages.emplace_back(
3895             makeShaderStageCreateInfo(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, *tessControlModule));
3896         shaderStages.emplace_back(
3897             makeShaderStageCreateInfo(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, *tessEvalModule));
3898     }
3899     else if (m_params.isGeometry())
3900     {
3901         geomModule =
3902             createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_GEOMETRY_BIT), 0u);
3903 
3904         shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_GEOMETRY_BIT, *geomModule));
3905     }
3906 
3907     VkPipelineVertexInputStateCreateInfo vertexInputState = initVulkanStructure();
3908     // No vertex input
3909 
3910     VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = initVulkanStructure();
3911     inputAssemblyState.topology =
3912         !!tessControlModule ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
3913 
3914     VkPipelineTessellationStateCreateInfo tesselationState = initVulkanStructure();
3915     tesselationState.patchControlPoints                    = 3;
3916 
3917     VkViewport viewport = makeViewport(m_renderArea.extent);
3918 
3919     VkPipelineViewportStateCreateInfo viewportState = initVulkanStructure();
3920     viewportState.viewportCount                     = 1;
3921     viewportState.pViewports                        = &viewport;
3922     viewportState.scissorCount                      = 1;
3923     viewportState.pScissors                         = &m_renderArea;
3924 
3925     VkPipelineRasterizationStateCreateInfo rasterizationState = initVulkanStructure();
3926     rasterizationState.depthClampEnable                       = VK_FALSE;
3927     rasterizationState.rasterizerDiscardEnable                = VK_FALSE;
3928     rasterizationState.polygonMode                            = VK_POLYGON_MODE_FILL;
3929     rasterizationState.cullMode                               = VK_CULL_MODE_NONE;
3930     rasterizationState.frontFace                              = VK_FRONT_FACE_COUNTER_CLOCKWISE;
3931     rasterizationState.depthBiasEnable                        = VK_FALSE;
3932     rasterizationState.depthBiasConstantFactor                = 0.0f;
3933     rasterizationState.depthBiasClamp                         = 0.0f;
3934     rasterizationState.depthBiasSlopeFactor                   = 0.0f;
3935     rasterizationState.lineWidth                              = 1.0f;
3936 
3937     VkPipelineMultisampleStateCreateInfo multisampleState = initVulkanStructure();
3938     // Everything else disabled/default
3939     multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
3940 
3941     VkPipelineDepthStencilStateCreateInfo depthStencilState = initVulkanStructure();
3942     // Everything else disabled/default
3943     depthStencilState.minDepthBounds = 0.0f;
3944     depthStencilState.maxDepthBounds = 1.0f;
3945 
3946     VkPipelineColorBlendAttachmentState colorAttachment{};
3947     // Everything else disabled/default
3948     colorAttachment.colorWriteMask =
3949         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
3950 
3951     VkPipelineColorBlendStateCreateInfo colorBlendState = initVulkanStructure();
3952     // Everything else disabled/default
3953     colorBlendState.attachmentCount = 1;
3954     colorBlendState.pAttachments    = &colorAttachment;
3955 
3956     {
3957         VkGraphicsPipelineCreateInfo createInfo = initVulkanStructure();
3958         createInfo.stageCount                   = u32(shaderStages.size());
3959         createInfo.pStages                      = shaderStages.data();
3960         createInfo.pVertexInputState            = &vertexInputState;
3961         createInfo.pInputAssemblyState          = &inputAssemblyState;
3962         createInfo.pTessellationState           = m_params.isTessellation() ? &tesselationState : nullptr;
3963         createInfo.pViewportState               = &viewportState;
3964         createInfo.pRasterizationState          = &rasterizationState;
3965         createInfo.pMultisampleState            = &multisampleState;
3966         createInfo.pDepthStencilState           = &depthStencilState;
3967         createInfo.pColorBlendState             = &colorBlendState;
3968         createInfo.pDynamicState                = nullptr;
3969         createInfo.layout                       = *m_pipelineLayout;
3970         createInfo.renderPass                   = *m_renderPass;
3971         createInfo.subpass                      = 0;
3972         createInfo.basePipelineHandle           = DE_NULL;
3973         createInfo.basePipelineIndex            = -1;
3974         createInfo.flags                        = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
3975 
3976         m_pipeline = vk::createGraphicsPipeline(*m_deviceInterface, *m_device,
3977                                                 DE_NULL, // pipeline cache
3978                                                 &createInfo);
3979     }
3980 }
3981 
createBufferForBinding(ResourceHolder & resources,VkDescriptorType descriptorType,VkBufferCreateInfo createInfo,bool isResultBuffer) const3982 void DescriptorBufferTestInstance::createBufferForBinding(ResourceHolder &resources, VkDescriptorType descriptorType,
3983                                                           VkBufferCreateInfo createInfo, bool isResultBuffer) const
3984 {
3985     auto &bufferResource    = resources.buffer;
3986     auto &captureReplayData = resources.captureReplay.bufferData;
3987 
3988     createInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
3989 
3990     if (!isResultBuffer && isCaptureDescriptor(descriptorType))
3991     {
3992         createInfo.flags |= VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
3993 
3994         DE_ASSERT(!bufferResource.buffer);
3995         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3996 
3997         VkBufferCaptureDescriptorDataInfoEXT info = initVulkanStructure();
3998         info.buffer                               = *bufferResource.buffer;
3999 
4000         DE_ASSERT(captureReplayData.empty());
4001         captureReplayData.resize(m_descriptorBufferProperties.bufferCaptureReplayDescriptorDataSize);
4002 
4003         VK_CHECK(
4004             m_deviceInterface->getBufferOpaqueCaptureDescriptorDataEXT(*m_device, &info, captureReplayData.data()));
4005     }
4006     else if (!isResultBuffer && isReplayDescriptor(descriptorType))
4007     {
4008         // Free the previous buffer and its memory
4009         reset(bufferResource.buffer);
4010         reset(bufferResource.alloc);
4011 
4012         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
4013         info.opaqueCaptureDescriptorData                = captureReplayData.data();
4014 
4015         createInfo.flags |= VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4016         createInfo.pNext = &info;
4017 
4018         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
4019     }
4020     else
4021     {
4022         DE_ASSERT(!bufferResource.buffer);
4023         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
4024     }
4025 
4026     auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferResource.buffer);
4027 
4028     VkMemoryOpaqueCaptureAddressAllocateInfo opaqueCaptureAddressAllocateInfo = initVulkanStructure();
4029     VkMemoryAllocateFlagsInfo allocFlagsInfo                                  = initVulkanStructure();
4030     allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
4031 
4032     if (!isResultBuffer && m_params.isCaptureReplayDescriptor(descriptorType))
4033     {
4034         allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT;
4035         allocFlagsInfo.pNext = &opaqueCaptureAddressAllocateInfo;
4036 
4037         if (isCaptureDescriptor(descriptorType))
4038         {
4039             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = 0ull;
4040         }
4041         else if (isReplayDescriptor(descriptorType))
4042         {
4043             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = bufferResource.opaqueCaptureAddress;
4044         }
4045     }
4046 
4047     DE_ASSERT(!bufferResource.alloc);
4048     bufferResource.alloc = allocate(memReqs, MemoryRequirement::HostVisible, &allocFlagsInfo);
4049 
4050     if (isCaptureDescriptor(descriptorType))
4051     {
4052         VkDeviceMemoryOpaqueCaptureAddressInfo memoryOpaqueCaptureAddressInfo = initVulkanStructure();
4053 
4054         memoryOpaqueCaptureAddressInfo.memory = bufferResource.alloc->getMemory();
4055 
4056         bufferResource.opaqueCaptureAddress =
4057             m_deviceInterface->getDeviceMemoryOpaqueCaptureAddress(*m_device, &memoryOpaqueCaptureAddressInfo);
4058     }
4059 
4060     VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *bufferResource.buffer, bufferResource.alloc->getMemory(),
4061                                                  bufferResource.alloc->getOffset()));
4062 
4063     bufferResource.loadDeviceAddress(*m_deviceInterface, *m_device);
4064 }
4065 
createImageForBinding(ResourceHolder & resources,VkDescriptorType descriptorType) const4066 void DescriptorBufferTestInstance::createImageForBinding(ResourceHolder &resources,
4067                                                          VkDescriptorType descriptorType) const
4068 {
4069     auto &imageResource = resources.image;
4070 
4071     // Image
4072     auto &captureReplayData = resources.captureReplay.imageData;
4073 
4074     if (isCaptureDescriptor(descriptorType))
4075     {
4076         imageResource.info.flags |= VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4077 
4078         DE_ASSERT(!imageResource.image);
4079         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4080 
4081         VkImageCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4082         info.image                               = *imageResource.image;
4083 
4084         DE_ASSERT(captureReplayData.empty());
4085         captureReplayData.resize(m_descriptorBufferProperties.imageCaptureReplayDescriptorDataSize);
4086 
4087         VK_CHECK(m_deviceInterface->getImageOpaqueCaptureDescriptorDataEXT(*m_device, &info, captureReplayData.data()));
4088     }
4089     else if (isReplayDescriptor(descriptorType))
4090     {
4091         // Free the previous image, its memory and the image view
4092         reset(imageResource.image);
4093         reset(imageResource.alloc);
4094         reset(imageResource.imageView);
4095 
4096         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
4097         info.opaqueCaptureDescriptorData                = captureReplayData.data();
4098 
4099         imageResource.info.flags |= VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4100         imageResource.info.pNext = &info;
4101 
4102         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4103     }
4104     else
4105     {
4106         DE_ASSERT(!imageResource.image);
4107         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4108     }
4109 
4110     // Memory allocation
4111     auto memReqs = getImageMemoryRequirements(*m_deviceInterface, *m_device, *imageResource.image);
4112 
4113     VkMemoryOpaqueCaptureAddressAllocateInfo opaqueCaptureAddressAllocateInfo = initVulkanStructure();
4114     VkMemoryAllocateFlagsInfo allocFlagsInfo                                  = initVulkanStructure();
4115 
4116     if (m_params.isCaptureReplayDescriptor(descriptorType))
4117     {
4118         allocFlagsInfo.flags |=
4119             VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT | VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
4120         allocFlagsInfo.pNext = &opaqueCaptureAddressAllocateInfo;
4121 
4122         if (isCaptureDescriptor(descriptorType))
4123         {
4124             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = 0ull;
4125         }
4126         else if (isReplayDescriptor(descriptorType))
4127         {
4128             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = imageResource.opaqueCaptureAddress;
4129         }
4130     }
4131 
4132     DE_ASSERT(!imageResource.alloc);
4133     imageResource.sizeBytes = memReqs.size;
4134     imageResource.alloc     = allocate(memReqs, MemoryRequirement::Local, &allocFlagsInfo);
4135 
4136     if (isCaptureDescriptor(descriptorType))
4137     {
4138         VkDeviceMemoryOpaqueCaptureAddressInfo memoryOpaqueCaptureAddressInfo = initVulkanStructure();
4139 
4140         memoryOpaqueCaptureAddressInfo.memory = imageResource.alloc->getMemory();
4141 
4142         imageResource.opaqueCaptureAddress =
4143             m_deviceInterface->getDeviceMemoryOpaqueCaptureAddress(*m_device, &memoryOpaqueCaptureAddressInfo);
4144     }
4145 
4146     VK_CHECK(m_deviceInterface->bindImageMemory(*m_device, *imageResource.image, imageResource.alloc->getMemory(),
4147                                                 imageResource.alloc->getOffset()));
4148 
4149     // Image view
4150     {
4151         auto &captureReplayDataView = resources.captureReplay.imageViewData;
4152 
4153         DE_ASSERT(imageResource.info.imageType == VK_IMAGE_TYPE_2D);
4154 
4155         VkImageViewCreateInfo createInfo = initVulkanStructure();
4156         createInfo.image                 = *imageResource.image;
4157         createInfo.viewType              = VK_IMAGE_VIEW_TYPE_2D;
4158         createInfo.format                = imageResource.info.format;
4159         createInfo.components            = ComponentMappingIdentity;
4160         createInfo.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
4161 
4162         if (isCaptureDescriptor(descriptorType))
4163         {
4164             createInfo.flags |= VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4165 
4166             DE_ASSERT(!imageResource.imageView);
4167             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4168 
4169             VkImageViewCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4170             info.imageView                               = *imageResource.imageView;
4171 
4172             DE_ASSERT(captureReplayDataView.empty());
4173             captureReplayDataView.resize(m_descriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize);
4174 
4175             VK_CHECK(m_deviceInterface->getImageViewOpaqueCaptureDescriptorDataEXT(*m_device, &info,
4176                                                                                    captureReplayDataView.data()));
4177         }
4178         else if (isReplayDescriptor(descriptorType))
4179         {
4180             VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
4181             info.opaqueCaptureDescriptorData                = captureReplayDataView.data();
4182 
4183             createInfo.flags |= VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4184             createInfo.pNext = &info;
4185 
4186             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4187         }
4188         else
4189         {
4190             VkSamplerYcbcrConversionInfo samplerYcbcrConvInfo = initVulkanStructure();
4191 
4192             if (resources.samplerYcbcrConversion)
4193             {
4194                 DE_ASSERT(m_params.variant == TestVariant::YCBCR_SAMPLER);
4195 
4196                 samplerYcbcrConvInfo.conversion = *resources.samplerYcbcrConversion;
4197 
4198                 createInfo.pNext = &samplerYcbcrConvInfo;
4199             }
4200 
4201             // No assertion here, as we must create a new view to go with the image.
4202             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4203         }
4204     }
4205 }
4206 
4207 // This function prepares a descriptor binding for use:
4208 // - Create necessary buffer/image resources and initialize them
4209 // - Write descriptor data into the descriptor buffer
4210 // - Fix the memory layout of combined image samplers (if needed)
4211 //
initializeBinding(const DescriptorSetLayoutHolder & dsl,uint32_t setIndex,Binding & binding)4212 void DescriptorBufferTestInstance::initializeBinding(const DescriptorSetLayoutHolder &dsl, uint32_t setIndex,
4213                                                      Binding &binding)
4214 {
4215     const auto arrayCount =
4216         (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ? 1 : binding.descriptorCount;
4217 
4218     const bool mustSplitCombinedImageSampler =
4219         (arrayCount > 1) && (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
4220         (m_descriptorBufferProperties.combinedImageSamplerDescriptorSingleArray == VK_FALSE);
4221 
4222     const bool isRobustBufferAccess = (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS);
4223     const bool isNullDescriptor     = (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) &&
4224                                   (binding.descriptorType == m_params.descriptor) && binding.isTestableDescriptor();
4225 
4226     for (uint32_t arrayIndex = 0; arrayIndex < arrayCount; ++arrayIndex)
4227     {
4228         VkDescriptorGetInfoEXT descGetInfo     = initVulkanStructure();
4229         VkDescriptorAddressInfoEXT addressInfo = initVulkanStructure();
4230         VkDescriptorImageInfo imageInfo{
4231             0, 0, VK_IMAGE_LAYOUT_UNDEFINED}; // must be explicitly initialized due to CTS handles inside
4232 
4233         descGetInfo.type = VK_DESCRIPTOR_TYPE_MAX_ENUM;
4234 
4235         if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
4236             (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER))
4237         {
4238             auto &resources      = getOrCreateResource(binding, arrayIndex);
4239             auto &bufferResource = resources.buffer;
4240 
4241             const VkBufferUsageFlags usage =
4242                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT :
4243                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT :
4244                                                                                 0;
4245             DE_ASSERT(usage);
4246 
4247             bufferResource.size =
4248                 sizeof(uint32_t) * (binding.isResultBuffer ? ConstResultBufferDwords : ConstUniformBufferDwords);
4249 
4250             createBufferForBinding(resources, binding.descriptorType, makeBufferCreateInfo(bufferResource.size, usage),
4251                                    binding.isResultBuffer);
4252 
4253             uint32_t *pBufferData = static_cast<uint32_t *>(bufferResource.alloc->getHostPtr());
4254 
4255             if (binding.isResultBuffer || isRobustBufferAccess)
4256             {
4257                 // We zero the buffer if it's a result buffer or if it's used with robust access.
4258                 deMemset(pBufferData, 0, static_cast<std::size_t>(bufferResource.size));
4259             }
4260             else
4261             {
4262                 const auto data = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4263 
4264                 for (uint32_t i = 0; i < ConstUniformBufferDwords; ++i)
4265                 {
4266                     pBufferData[i] = data + i;
4267                 }
4268             }
4269 
4270             addressInfo.address = bufferResource.deviceAddress;
4271             addressInfo.range   = bufferResource.size;
4272             addressInfo.format  = VK_FORMAT_UNDEFINED;
4273 
4274             DE_UNREF(ConstRobustBufferAlignment);
4275             DE_ASSERT(binding.isResultBuffer || !isRobustBufferAccess ||
4276                       ((addressInfo.range % ConstRobustBufferAlignment) == 0));
4277 
4278             descGetInfo.type                = binding.descriptorType;
4279             descGetInfo.data.pUniformBuffer = isNullDescriptor ? nullptr : &addressInfo; // and pStorageBuffer
4280         }
4281         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4282         {
4283             // Inline uniforms don't use a backing buffer.
4284             DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID);
4285         }
4286         else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
4287                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
4288         {
4289             auto &resources      = getOrCreateResource(binding, arrayIndex);
4290             auto &bufferResource = resources.buffer;
4291 
4292             const VkBufferUsageFlags usage = (binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ?
4293                                                  VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT :
4294                                              (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ?
4295                                                  VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT :
4296                                                  0;
4297             DE_ASSERT(usage);
4298 
4299             bufferResource.size = ConstTexelBufferElements * sizeof(uint32_t);
4300 
4301             createBufferForBinding(resources, binding.descriptorType, makeBufferCreateInfo(bufferResource.size, usage),
4302                                    binding.isResultBuffer);
4303 
4304             if (m_params.isPushDescriptorTest())
4305             {
4306                 // Push descriptors use buffer views.
4307                 auto &bufferViewResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).bufferView;
4308 
4309                 bufferViewResource = makeBufferView(*m_deviceInterface, *m_device, *bufferResource.buffer,
4310                                                     VK_FORMAT_R32_UINT, 0, bufferResource.size);
4311             }
4312 
4313             uint32_t *pBufferData = static_cast<uint32_t *>(bufferResource.alloc->getHostPtr());
4314 
4315             if (isRobustBufferAccess)
4316             {
4317                 // Zero the buffer used with robust access.
4318                 deMemset(pBufferData, 0, static_cast<std::size_t>(bufferResource.size));
4319             }
4320             else
4321             {
4322                 const auto data = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4323 
4324                 for (uint32_t i = 0; i < ConstTexelBufferElements; ++i)
4325                 {
4326                     pBufferData[i] = data + i;
4327                 }
4328             }
4329 
4330             addressInfo.address = bufferResource.deviceAddress;
4331             addressInfo.range   = bufferResource.size;
4332             addressInfo.format  = VK_FORMAT_R32_UINT;
4333 
4334             DE_UNREF(ConstRobustBufferAlignment);
4335             DE_ASSERT(!isRobustBufferAccess || ((addressInfo.range % ConstRobustBufferAlignment) == 0));
4336 
4337             descGetInfo.type                     = binding.descriptorType;
4338             descGetInfo.data.pUniformTexelBuffer = isNullDescriptor ? nullptr : &addressInfo; // and pStorageTexelBuffer
4339         }
4340         else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
4341                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
4342                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
4343                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
4344         {
4345             // Check if we had already added the resource while handling samplers.
4346             auto &resources     = getOrCreateResource(binding, arrayIndex);
4347             auto &imageResource = resources.image;
4348             auto &stagingBuffer = resources.buffer;
4349 
4350             {
4351                 VkImageLayout layout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4352                 VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
4353 
4354                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
4355                 {
4356                     usage |= VK_IMAGE_USAGE_STORAGE_BIT;
4357                     layout = VK_IMAGE_LAYOUT_GENERAL;
4358                 }
4359                 else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
4360                 {
4361                     usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
4362                 }
4363                 else
4364                 {
4365                     usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
4366                 }
4367 
4368                 // We ensure the extent matches the render area, for the sake of input attachment case.
4369                 imageResource.info                       = initVulkanStructure();
4370                 imageResource.info.flags                 = 0;
4371                 imageResource.info.imageType             = VK_IMAGE_TYPE_2D;
4372                 imageResource.info.format                = m_imageColorFormat;
4373                 imageResource.info.extent.width          = m_renderArea.extent.width;
4374                 imageResource.info.extent.height         = m_renderArea.extent.height;
4375                 imageResource.info.extent.depth          = 1;
4376                 imageResource.info.mipLevels             = 1;
4377                 imageResource.info.arrayLayers           = 1;
4378                 imageResource.info.samples               = VK_SAMPLE_COUNT_1_BIT;
4379                 imageResource.info.tiling                = VK_IMAGE_TILING_OPTIMAL;
4380                 imageResource.info.usage                 = usage;
4381                 imageResource.info.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4382                 imageResource.info.queueFamilyIndexCount = 0;
4383                 imageResource.info.pQueueFamilyIndices   = nullptr;
4384                 imageResource.info.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
4385 
4386                 createImageForBinding(resources, binding.descriptorType);
4387 
4388                 imageResource.layout = layout;
4389 
4390                 imageInfo.imageLayout = layout;
4391                 imageInfo.imageView   = *imageResource.imageView;
4392 
4393                 descGetInfo.type = binding.descriptorType;
4394 
4395                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
4396                 {
4397                     if (isNullDescriptor)
4398                         imageInfo.imageView = DE_NULL;
4399 
4400                     descGetInfo.data.pCombinedImageSampler = &imageInfo;
4401                 }
4402                 else
4403                     descGetInfo.data.pStorageImage = isNullDescriptor ? nullptr : &imageInfo;
4404             }
4405             {
4406                 const auto numPixels = m_renderArea.extent.width * m_renderArea.extent.height; // plane 0
4407 
4408                 if (m_imageColorFormat == VK_FORMAT_R32_UINT)
4409                 {
4410                     stagingBuffer.size = sizeof(uint32_t) * numPixels;
4411                 }
4412                 else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
4413                 {
4414                     DE_ASSERT((m_renderArea.extent.width % 2) == 0);
4415                     DE_ASSERT((m_renderArea.extent.height % 2) == 0);
4416 
4417                     stagingBuffer.size = 1 * numPixels;      // g8
4418                     stagingBuffer.size += 2 * numPixels / 4; // b8r8
4419                 }
4420                 else
4421                 {
4422                     DE_ASSERT(0);
4423                 }
4424 
4425                 auto createInfo = makeBufferCreateInfo(stagingBuffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
4426 
4427                 stagingBuffer.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
4428 
4429                 auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *stagingBuffer.buffer);
4430 
4431                 stagingBuffer.alloc = allocate(memReqs, MemoryRequirement::HostVisible);
4432 
4433                 VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *stagingBuffer.buffer,
4434                                                              stagingBuffer.alloc->getMemory(),
4435                                                              stagingBuffer.alloc->getOffset()));
4436 
4437                 // Fill the whole image uniformly
4438                 if (m_imageColorFormat == VK_FORMAT_R32_UINT)
4439                 {
4440                     auto pBufferData = static_cast<uint32_t *>(stagingBuffer.alloc->getHostPtr());
4441                     uint32_t expectedData;
4442 
4443                     if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
4444                     {
4445                         expectedData = getExpectedData(m_params.hash, setIndex, binding.binding,
4446                                                        binding.inputAttachmentIndex + arrayIndex);
4447                     }
4448                     else
4449                     {
4450                         expectedData = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4451                     }
4452 
4453                     std::fill(pBufferData, pBufferData + numPixels, expectedData);
4454                 }
4455                 else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
4456                 {
4457                     auto pPlane0 = static_cast<uint8_t *>(stagingBuffer.alloc->getHostPtr());
4458                     auto pPlane1 = static_cast<uint16_t *>(offsetPtr(pPlane0, numPixels));
4459                     const auto expectedData =
4460                         getExpectedData_G8_B8R8(m_params.hash, setIndex, binding.binding, arrayIndex);
4461 
4462                     std::fill(pPlane0, pPlane0 + numPixels, expectedData.x());
4463                     std::fill(pPlane1, pPlane1 + numPixels / 4, expectedData.y());
4464                 }
4465                 else
4466                 {
4467                     DE_ASSERT(0);
4468                 }
4469             }
4470 
4471             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
4472             {
4473                 DE_ASSERT(m_params.variant != TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS);
4474 
4475                 DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4476                 auto &resourceSampler = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4477 
4478                 imageInfo.sampler = *resourceSampler;
4479             }
4480         }
4481         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
4482         {
4483             if (m_params.variant != TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
4484             {
4485                 DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4486                 auto &resourceSampler = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4487 
4488                 descGetInfo.type          = binding.descriptorType;
4489                 descGetInfo.data.pSampler = &*resourceSampler;
4490             }
4491         }
4492         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
4493         {
4494             Allocator &allocator        = *m_allocatorPtr;
4495             const uint32_t expectedData = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4496             const float zDepth          = float(expectedData);
4497             const std::vector<tcu::Vec3> vertices{
4498                 tcu::Vec3(-1.0f, -1.0f, zDepth), tcu::Vec3(-1.0f, 1.0f, zDepth), tcu::Vec3(1.0f, -1.0f, zDepth),
4499 
4500                 tcu::Vec3(-1.0f, 1.0f, zDepth),  tcu::Vec3(1.0f, 1.0f, zDepth),  tcu::Vec3(1.0f, -1.0f, zDepth),
4501             };
4502             auto &resources              = getOrCreateResource(binding, arrayIndex);
4503             const bool replayableBinding = binding.isTestableDescriptor();
4504             VkAccelerationStructureCreateFlagsKHR createFlags =
4505                 (m_params.isCaptureReplayDescriptor(binding.descriptorType) && replayableBinding) ?
4506                     static_cast<VkAccelerationStructureCreateFlagsKHR>(
4507                         VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT) :
4508                     static_cast<VkAccelerationStructureCreateFlagsKHR>(0u);
4509             vk::MemoryRequirement memoryReqs =
4510                 (m_params.isCaptureReplayDescriptor(binding.descriptorType) && replayableBinding) ?
4511                     MemoryRequirement::DeviceAddressCaptureReplay :
4512                     MemoryRequirement::Any;
4513             VkOpaqueCaptureDescriptorDataCreateInfoEXT infos[]     = {initVulkanStructure(), initVulkanStructure()};
4514             VkOpaqueCaptureDescriptorDataCreateInfoEXT *infoPtrs[] = {DE_NULL, DE_NULL};
4515 
4516             if (isReplayDescriptor(binding.descriptorType) && replayableBinding)
4517             {
4518                 resources.rtBlas.clear();
4519                 resources.rtTlas.clear();
4520 
4521                 std::vector<uint8_t> *captureReplayDatas[] = {&resources.captureReplay.accelerationStructureDataBlas,
4522                                                               &resources.captureReplay.accelerationStructureDataTlas};
4523 
4524                 for (int ndx = 0; ndx < 2; ++ndx)
4525                 {
4526                     std::vector<uint8_t> &captureReplayData          = *captureReplayDatas[ndx];
4527                     VkOpaqueCaptureDescriptorDataCreateInfoEXT &info = infos[ndx];
4528 
4529                     info.opaqueCaptureDescriptorData = captureReplayData.data();
4530                     infoPtrs[ndx]                    = &infos[ndx];
4531                 }
4532             }
4533 
4534             {
4535                 DE_ASSERT(resources.rtBlas.get() == DE_NULL);
4536 
4537                 resources.rtBlas =
4538                     de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
4539                 if (binding.isRayTracingAS)
4540                     resources.rtBlas->setDefaultGeometryData(m_params.stage);
4541                 else
4542                     resources.rtBlas->setGeometryData(vertices, true);
4543                 resources.rtBlas->setCreateFlags(createFlags);
4544                 resources.rtBlas->create(*m_deviceInterface, *m_device, allocator, 0, 0, infoPtrs[0], memoryReqs);
4545             }
4546 
4547             {
4548                 DE_ASSERT(resources.rtTlas.get() == DE_NULL);
4549 
4550                 resources.rtTlas = makeTopLevelAccelerationStructure();
4551                 resources.rtTlas->addInstance(resources.rtBlas);
4552                 resources.rtTlas->setCreateFlags(createFlags);
4553                 resources.rtTlas->create(*m_deviceInterface, *m_device, allocator, 0, 0, infoPtrs[1], memoryReqs);
4554             }
4555 
4556             if (isCaptureDescriptor(binding.descriptorType) && replayableBinding)
4557             {
4558                 const VkAccelerationStructureKHR *accelerationStructures[] = {resources.rtBlas->getPtr(),
4559                                                                               resources.rtTlas->getPtr()};
4560                 std::vector<uint8_t> *captureReplayDatas[] = {&resources.captureReplay.accelerationStructureDataBlas,
4561                                                               &resources.captureReplay.accelerationStructureDataTlas};
4562 
4563                 for (int ndx = 0; ndx < 2; ++ndx)
4564                 {
4565                     VkAccelerationStructureCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4566                     const VkAccelerationStructureKHR *accelerationStructure  = accelerationStructures[ndx];
4567                     std::vector<uint8_t> &captureReplayData                  = *captureReplayDatas[ndx];
4568 
4569                     DE_ASSERT(accelerationStructure != DE_NULL && *accelerationStructure != DE_NULL);
4570                     DE_ASSERT(captureReplayData.empty());
4571 
4572                     info.accelerationStructure = *accelerationStructure;
4573 
4574                     captureReplayData.resize(
4575                         m_descriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize);
4576 
4577                     VK_CHECK(m_deviceInterface->getAccelerationStructureOpaqueCaptureDescriptorDataEXT(
4578                         *m_device, &info, captureReplayData.data()));
4579                 }
4580             }
4581 
4582             descGetInfo.type = binding.descriptorType;
4583             descGetInfo.data.accelerationStructure =
4584                 isNullDescriptor ?
4585                     DE_NULL :
4586                     getAccelerationStructureDeviceAddress(*m_deviceInterface, *m_device, *resources.rtTlas->getPtr());
4587         }
4588         else
4589         {
4590             TCU_THROW(InternalError, "Not implemented");
4591         }
4592 
4593         if (dsl.usePushDescriptors || dsl.sizeOfLayout == 0)
4594         {
4595             // Push descriptors don't rely on descriptor buffers, move to the next binding.
4596             continue;
4597         }
4598 
4599         // Write the descriptor at the right offset in the descriptor buffer memory.
4600         // - With inline uniform blocks, we write the uniform data into the descriptor buffer directly.
4601         // - With regular descriptors, the written memory is opaque to us (same goes for null descriptors).
4602         {
4603             void *bindingHostPtr = nullptr;
4604             Allocation *pAlloc   = nullptr;
4605             auto arrayOffset     = arrayIndex * getDescriptorSize(binding);
4606 
4607             if (dsl.stagingBufferOffset == OFFSET_UNUSED)
4608             {
4609                 const auto &descriptorBuffer = *m_descriptorBuffers[dsl.bufferIndex];
4610                 const auto bufferHostPtr     = offsetPtr(descriptorBuffer.alloc->getHostPtr(), dsl.bufferOffset);
4611 
4612                 bindingHostPtr = offsetPtr(bufferHostPtr, binding.offset);
4613                 pAlloc         = descriptorBuffer.alloc.get();
4614             }
4615             else
4616             {
4617                 bindingHostPtr =
4618                     offsetPtr(m_descriptorStagingBuffer.alloc->getHostPtr(), dsl.stagingBufferOffset + binding.offset);
4619 
4620                 pAlloc = m_descriptorStagingBuffer.alloc.get();
4621             }
4622 
4623             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4624             {
4625                 DE_ASSERT(arrayIndex == 0);
4626 
4627                 // Inline uniform data is written in descriptor buffer directly.
4628                 const auto numDwords = binding.descriptorCount / sizeof(uint32_t);
4629                 const auto data      = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4630 
4631                 uint32_t *pInlineData = static_cast<uint32_t *>(bindingHostPtr);
4632 
4633                 for (uint32_t i = 0; i < numDwords; ++i)
4634                 {
4635                     pInlineData[i] = data + i;
4636                 }
4637             }
4638             else if (isReplayDescriptor(binding.descriptorType))
4639             {
4640                 // We're expecting that a descriptor based on replayed resources will have exactly the same binary data.
4641                 // Copy it and compare after obtaining the new descriptor.
4642                 //
4643                 auto descriptorPtr        = offsetPtr(bindingHostPtr, arrayOffset);
4644                 const auto descriptorSize = static_cast<size_t>(getDescriptorTypeSize(descGetInfo.type));
4645 
4646                 std::vector<uint8_t> reference(descriptorSize);
4647                 deMemcpy(reference.data(), descriptorPtr, descriptorSize);
4648 
4649                 deMemset(descriptorPtr, 0xcc, descriptorSize);
4650                 m_deviceInterface->getDescriptorEXT(*m_device, &descGetInfo, descriptorSize, descriptorPtr);
4651 
4652                 if (deMemCmp(reference.data(), descriptorPtr, descriptorSize) != 0)
4653                 {
4654                     TCU_THROW(TestError, "Replayed descriptor differs from the captured descriptor");
4655                 }
4656             }
4657             else
4658             {
4659                 auto descriptorPtr        = offsetPtr(bindingHostPtr, arrayOffset);
4660                 const auto descriptorSize = static_cast<size_t>(getDescriptorTypeSize(descGetInfo.type));
4661                 m_deviceInterface->getDescriptorEXT(*m_device, &descGetInfo, descriptorSize, descriptorPtr);
4662             }
4663 
4664             // After writing the last array element, rearrange the split combined image sampler data.
4665             if (mustSplitCombinedImageSampler && ((arrayIndex + 1) == arrayCount))
4666             {
4667                 // We determined the size of the descriptor set layout on the VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type,
4668                 // so it's expected the following holds true.
4669                 DE_ASSERT((m_descriptorBufferProperties.sampledImageDescriptorSize +
4670                            m_descriptorBufferProperties.samplerDescriptorSize) ==
4671                           m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4672 
4673                 std::vector<uint8_t> scratchSpace(arrayCount *
4674                                                   m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4675 
4676                 const auto descriptorArraySize = static_cast<std::size_t>(
4677                     arrayCount * m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4678 
4679                 deMemcpy(scratchSpace.data(), bindingHostPtr, descriptorArraySize);
4680                 deMemset(bindingHostPtr, 0, descriptorArraySize);
4681 
4682                 const void *combinedReadPtr = scratchSpace.data();
4683                 void *imageWritePtr         = bindingHostPtr;
4684                 void *samplerWritePtr =
4685                     offsetPtr(bindingHostPtr, arrayCount * m_descriptorBufferProperties.sampledImageDescriptorSize);
4686 
4687                 for (uint32_t i = 0; i < arrayCount; ++i)
4688                 {
4689                     deMemcpy(imageWritePtr, offsetPtr(combinedReadPtr, 0),
4690                              m_descriptorBufferProperties.sampledImageDescriptorSize);
4691                     deMemcpy(samplerWritePtr,
4692                              offsetPtr(combinedReadPtr, m_descriptorBufferProperties.sampledImageDescriptorSize),
4693                              m_descriptorBufferProperties.samplerDescriptorSize);
4694 
4695                     combinedReadPtr =
4696                         offsetPtr(combinedReadPtr, m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4697                     imageWritePtr   = offsetPtr(imageWritePtr, m_descriptorBufferProperties.sampledImageDescriptorSize);
4698                     samplerWritePtr = offsetPtr(samplerWritePtr, m_descriptorBufferProperties.samplerDescriptorSize);
4699                 }
4700             }
4701 
4702             flushAlloc(*m_deviceInterface, *m_device, *pAlloc);
4703         }
4704     }
4705 }
4706 
4707 // Update a descriptor set with a push or a push template.
4708 //
pushDescriptorSet(VkCommandBuffer cmdBuf,VkPipelineBindPoint bindPoint,const DescriptorSetLayoutHolder & dsl,uint32_t setIndex) const4709 void DescriptorBufferTestInstance::pushDescriptorSet(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint,
4710                                                      const DescriptorSetLayoutHolder &dsl, uint32_t setIndex) const
4711 {
4712     std::vector<PushDescriptorData> descriptorData(dsl.bindings.size()); // Allocate empty elements upfront
4713     std::vector<VkWriteDescriptorSet> descriptorWrites;
4714     std::vector<VkWriteDescriptorSetAccelerationStructureKHR> descriptorWritesAccelerationStructures;
4715 
4716     descriptorWrites.reserve(dsl.bindings.size());
4717     descriptorWritesAccelerationStructures.reserve(dsl.bindings.size());
4718 
4719     // Fill in the descriptor data structure. It can be used by the regular and templated update path.
4720 
4721     for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
4722     {
4723         const auto &binding = dsl.bindings[bindingIndex];
4724 
4725         VkWriteDescriptorSet write = initVulkanStructure();
4726         write.dstSet               = DE_NULL; // ignored with push descriptors
4727         write.dstBinding           = bindingIndex;
4728         write.dstArrayElement      = 0;
4729         write.descriptorCount      = binding.descriptorCount;
4730         write.descriptorType       = binding.descriptorType;
4731 
4732         for (uint32_t arrayIndex = 0; arrayIndex < write.descriptorCount; ++arrayIndex)
4733         {
4734             DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4735 
4736             if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
4737                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER))
4738             {
4739                 const auto &bufferResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).buffer;
4740 
4741                 auto pInfo    = &descriptorData[bindingIndex].bufferInfos[arrayIndex];
4742                 pInfo->buffer = *bufferResource.buffer;
4743                 pInfo->offset = 0;
4744                 pInfo->range  = bufferResource.size;
4745 
4746                 if (arrayIndex == 0)
4747                 {
4748                     write.pBufferInfo = pInfo;
4749                 }
4750             }
4751             else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
4752                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
4753             {
4754                 const auto &bufferViewResource =
4755                     (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).bufferView;
4756 
4757                 auto pBufferView = &descriptorData[bindingIndex].texelBufferViews[arrayIndex];
4758                 *pBufferView     = *bufferViewResource;
4759 
4760                 if (arrayIndex == 0)
4761                 {
4762                     write.pTexelBufferView = pBufferView;
4763                 }
4764             }
4765             else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
4766                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
4767                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
4768                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
4769                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER))
4770             {
4771                 const auto &imageResource   = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).image;
4772                 const auto &samplerResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4773 
4774                 // Dereferencing unused resources will return null handles, so we can treat all these descriptors uniformly.
4775 
4776                 auto pInfo         = &descriptorData[bindingIndex].imageInfos[arrayIndex];
4777                 pInfo->imageView   = *imageResource.imageView;
4778                 pInfo->imageLayout = imageResource.layout;
4779                 pInfo->sampler     = *samplerResource;
4780 
4781                 if (arrayIndex == 0)
4782                 {
4783                     write.pImageInfo = pInfo;
4784                 }
4785             }
4786             else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
4787             {
4788                 const ResourceHolder &resources = **m_resources[binding.perBindingResourceIndex[arrayIndex]];
4789                 const VkAccelerationStructureKHR *accelerationStructurePtr = resources.rtTlas.get()->getPtr();
4790 
4791                 DE_ASSERT(accelerationStructurePtr != DE_NULL && *accelerationStructurePtr != DE_NULL);
4792 
4793                 descriptorData[bindingIndex].accelerationStructures[arrayIndex] = *accelerationStructurePtr;
4794 
4795                 if (arrayIndex == 0)
4796                 {
4797                     VkWriteDescriptorSetAccelerationStructureKHR descriptorWritesAccelerationStructure =
4798                         initVulkanStructure();
4799 
4800                     descriptorWritesAccelerationStructure.accelerationStructureCount = write.descriptorCount;
4801                     descriptorWritesAccelerationStructure.pAccelerationStructures =
4802                         descriptorData[bindingIndex].accelerationStructures;
4803 
4804                     descriptorWritesAccelerationStructures.emplace_back(descriptorWritesAccelerationStructure);
4805 
4806                     write.pNext =
4807                         &descriptorWritesAccelerationStructures[descriptorWritesAccelerationStructures.size() - 1];
4808                 }
4809             }
4810             else
4811             {
4812                 TCU_THROW(InternalError, "Not implemented");
4813             }
4814         }
4815 
4816         if (m_params.variant == TestVariant::PUSH_DESCRIPTOR)
4817         {
4818             descriptorWrites.emplace_back(write);
4819         }
4820     }
4821 
4822     if (m_params.variant == TestVariant::PUSH_DESCRIPTOR)
4823     {
4824         if (m_params.commands2)
4825         {
4826             vk::VkPushDescriptorSetInfoKHR pushDescriptorSetInfo = {
4827                 VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR, // VkStructureType sType;
4828                 DE_NULL,                                        // const void* pNext;
4829                 (VkShaderStageFlags)m_params.stage,             // VkShaderStageFlags stageFlags;
4830                 *m_pipelineLayout,                              // VkPipelineLayout layout;
4831                 setIndex,                                       // uint32_t set;
4832                 u32(descriptorWrites.size()),                   // uint32_t descriptorWriteCount;
4833                 descriptorWrites.data()                         // const VkWriteDescriptorSet* pDescriptorWrites;
4834             };
4835             m_deviceInterface->cmdPushDescriptorSet2KHR(cmdBuf, &pushDescriptorSetInfo);
4836         }
4837         else
4838         {
4839             m_deviceInterface->cmdPushDescriptorSetKHR(cmdBuf, bindPoint, *m_pipelineLayout, setIndex,
4840                                                        u32(descriptorWrites.size()), descriptorWrites.data());
4841         }
4842     }
4843     else if (m_params.variant == TestVariant::PUSH_TEMPLATE)
4844     {
4845         std::vector<VkDescriptorUpdateTemplateEntry> updateEntries(descriptorData.size()); // preallocate
4846 
4847         const auto dataBasePtr = reinterpret_cast<uint8_t *>(descriptorData.data());
4848 
4849         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
4850         {
4851             const auto &binding = dsl.bindings[bindingIndex];
4852             const auto &data    = descriptorData[bindingIndex];
4853 
4854             auto &entry           = updateEntries[bindingIndex];
4855             entry.dstBinding      = binding.binding;
4856             entry.dstArrayElement = 0;
4857             entry.descriptorCount = binding.descriptorCount;
4858             entry.descriptorType  = binding.descriptorType;
4859 
4860             switch (binding.descriptorType)
4861             {
4862             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
4863             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
4864                 entry.offset = basePtrOffsetOf(dataBasePtr, data.bufferInfos);
4865                 entry.stride = sizeof(data.bufferInfos[0]);
4866                 break;
4867 
4868             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
4869             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
4870                 entry.offset = basePtrOffsetOf(dataBasePtr, data.texelBufferViews);
4871                 entry.stride = sizeof(data.texelBufferViews[0]);
4872                 break;
4873 
4874             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
4875             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
4876             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
4877             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
4878             case VK_DESCRIPTOR_TYPE_SAMPLER:
4879                 entry.offset = basePtrOffsetOf(dataBasePtr, data.imageInfos);
4880                 entry.stride = sizeof(data.imageInfos[0]);
4881                 break;
4882 
4883             case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
4884                 entry.offset = basePtrOffsetOf(dataBasePtr, data.accelerationStructures);
4885                 entry.stride = sizeof(data.accelerationStructures[0]);
4886                 break;
4887 
4888             default:
4889                 DE_ASSERT(0);
4890                 break;
4891             }
4892         }
4893 
4894         VkDescriptorUpdateTemplateCreateInfo createInfo = initVulkanStructure();
4895         createInfo.templateType                         = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR;
4896         createInfo.descriptorSetLayout                  = *dsl.layout;
4897         createInfo.pipelineBindPoint                    = bindPoint;
4898         createInfo.pipelineLayout                       = *m_pipelineLayout;
4899         createInfo.set                                  = setIndex;
4900         createInfo.descriptorUpdateEntryCount           = u32(updateEntries.size());
4901         createInfo.pDescriptorUpdateEntries             = updateEntries.data();
4902 
4903         auto descriptorUpdateTemplate = createDescriptorUpdateTemplate(*m_deviceInterface, *m_device, &createInfo);
4904 
4905         if (m_params.commands2)
4906         {
4907             vk::VkPushDescriptorSetWithTemplateInfoKHR pushDescriptorSetWithTemplateInfo = {
4908                 VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR, // VkStructureType sType;
4909                 DE_NULL,                                                      // const void* pNext;
4910                 *descriptorUpdateTemplate, // VkDescriptorUpdateTemplate descriptorUpdateTemplate;
4911                 *m_pipelineLayout,         // VkPipelineLayout layout;
4912                 setIndex,                  // uint32_t set;
4913                 dataBasePtr                // const void* pData;
4914             };
4915             m_deviceInterface->cmdPushDescriptorSetWithTemplate2KHR(cmdBuf, &pushDescriptorSetWithTemplateInfo);
4916         }
4917         else
4918         {
4919             m_deviceInterface->cmdPushDescriptorSetWithTemplateKHR(cmdBuf, *descriptorUpdateTemplate, *m_pipelineLayout,
4920                                                                    setIndex, dataBasePtr);
4921         }
4922     }
4923 }
4924 
4925 // Perform the test accoring to the parameters. At high level, all tests perform these steps:
4926 //
4927 // - Create a new device and queues, query extension properties.
4928 // - Fill descriptor set layouts and bindings, based on SimpleBinding's.
4929 // - Create samplers, if needed. Set immutable samplers in bindings.
4930 // - Create descriptor set layouts.
4931 //   - If mutable descriptor types are used, it affects: descriptor size and offset and descriptor set layout creation.
4932 //     However, the rest of the logic is largely unchanged and refers to the specific descriptor type used at runtime.
4933 // - Create descriptor buffers.
4934 // - Iterate over all bindings to:
4935 //   - Create their resources (images, buffers) and initialize them
4936 //   - Write bindings to descriptor buffer memory
4937 //   - Fix combined image samplers for arrayed bindings (if applicable)
4938 // - Create the pipeline layout, shaders, and the pipeline
4939 // - Create the command buffer and record the commands (barriers omitted for brevity):
4940 //   - Bind the pipeline and the descriptor buffers
4941 //   - Upload descriptor buffer data (with staged uploads)
4942 //   - Upload image data (if images are used)
4943 //   - Push descriptors (if used)
4944 //   - Dispatch or draw
4945 //   - Submit the commands
4946 //   - Map the result buffer to a host pointer
4947 //   - Verify the result and log diagnostic on a failure
4948 //
4949 // Verification logic is very simple.
4950 //
4951 // Each successful binding read will increment the result counter. If the shader got an unexpected value, the counter
4952 // will be less than expected. Additionally, the first failed set/binding/array index will be recorded.
4953 //
4954 // With capture/replay tests, iterate() will be called twice, splitting the test into capture and replay passes.
4955 // The capture pass saves the opaque data, while the replay pass uses it and compares the results.
4956 //
iterate()4957 tcu::TestStatus DescriptorBufferTestInstance::iterate()
4958 {
4959     DE_ASSERT(m_params.bufferBindingCount <= m_descriptorBufferProperties.maxDescriptorBufferBindings);
4960 
4961     const auto &vk = *m_deviceInterface;
4962 
4963     if (m_testIteration == 0)
4964     {
4965         uint32_t currentSet = INDEX_INVALID;
4966 
4967         uint32_t inlineUniformSize = 0u;
4968 
4969         for (const auto &sb : m_simpleBindings)
4970         {
4971             if ((currentSet == INDEX_INVALID) || (currentSet < sb.set))
4972             {
4973                 currentSet = sb.set;
4974 
4975                 addDescriptorSetLayout();
4976             }
4977 
4978             auto &dsl                     = **m_descriptorSetLayouts.back();
4979             VkShaderStageFlags stageFlags = sb.isRayTracingAS ?
4980                                                 static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_RAYGEN_BIT_KHR) :
4981                                                 static_cast<VkShaderStageFlags>(0u);
4982 
4983             Binding binding{};
4984             binding.binding              = sb.binding;
4985             binding.descriptorType       = sb.type;
4986             binding.stageFlags           = m_params.stage | stageFlags;
4987             binding.inputAttachmentIndex = sb.inputAttachmentIndex;
4988             binding.isResultBuffer       = sb.isResultBuffer;
4989             binding.isRayTracingAS       = sb.isRayTracingAS;
4990             binding.isMutableType        = (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE) &&
4991                                     sb.type != VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR &&
4992                                     maskCheck(m_params.mutableDescriptorTypes, sb.type);
4993 
4994             if (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4995             {
4996                 binding.descriptorCount = sizeof(uint32_t) * ConstInlineBlockDwords;
4997                 inlineUniformSize += binding.descriptorCount;
4998             }
4999             else
5000             {
5001                 binding.descriptorCount = sb.count;
5002             }
5003 
5004             if ((sb.type == VK_DESCRIPTOR_TYPE_SAMPLER) || (sb.type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5005             {
5006                 if (sb.isEmbeddedImmutableSampler)
5007                 {
5008                     dsl.hasEmbeddedImmutableSamplers = true;
5009                 }
5010             }
5011 
5012             if (m_params.isPushDescriptorTest() &&
5013                 (m_params.pushDescriptorSetIndex == (m_descriptorSetLayouts.size() - 1)))
5014             {
5015                 dsl.usePushDescriptors = true;
5016             }
5017 
5018             dsl.bindings.emplace_back(binding);
5019         }
5020 
5021         const VkPhysicalDeviceVulkan13Properties &vulkan13properties = m_context.getDeviceVulkan13Properties();
5022         if (m_context.getUsedApiVersion() >= VK_API_VERSION_1_3 &&
5023             inlineUniformSize > vulkan13properties.maxInlineUniformTotalSize)
5024         {
5025             TCU_THROW(NotSupportedError, "Test require more inline uniform total size among all stages. Provided " +
5026                                              de::toString(vulkan13properties.maxInlineUniformTotalSize));
5027         }
5028     }
5029 
5030     // We create samplers before creating the descriptor set layouts, in case we need to use
5031     // immutable (or embedded) samplers.
5032 
5033     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5034     {
5035         auto &dsl = **m_descriptorSetLayouts[setIndex];
5036 
5037         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5038         {
5039             auto &binding = dsl.bindings[bindingIndex];
5040 
5041             if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
5042                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5043             {
5044                 for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
5045                 {
5046                     if (binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID)
5047                     {
5048                         binding.perBindingResourceIndex[arrayIndex] = addResource();
5049                     }
5050 
5051                     auto &resources         = **m_resources[binding.perBindingResourceIndex[arrayIndex]];
5052                     auto &captureReplayData = resources.captureReplay.samplerData;
5053 
5054                     if (m_params.variant == TestVariant::YCBCR_SAMPLER)
5055                     {
5056                         VkSamplerYcbcrConversionCreateInfo convCreateInfo = initVulkanStructure();
5057                         convCreateInfo.format                             = m_imageColorFormat;
5058                         convCreateInfo.ycbcrModel                  = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
5059                         convCreateInfo.ycbcrRange                  = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
5060                         convCreateInfo.components                  = ComponentMappingIdentity;
5061                         convCreateInfo.xChromaOffset               = VK_CHROMA_LOCATION_COSITED_EVEN;
5062                         convCreateInfo.yChromaOffset               = VK_CHROMA_LOCATION_COSITED_EVEN;
5063                         convCreateInfo.chromaFilter                = VK_FILTER_NEAREST;
5064                         convCreateInfo.forceExplicitReconstruction = VK_FALSE;
5065 
5066                         resources.samplerYcbcrConversion = createSamplerYcbcrConversion(vk, *m_device, &convCreateInfo);
5067                     }
5068 
5069                     // Use CLAMP_TO_BORDER to verify that sampling outside the image will make use of the sampler's
5070                     // properties. The border color used must match the one in glslOutputVerification().
5071 
5072                     VkSamplerCreateInfo createInfo     = initVulkanStructure();
5073                     createInfo.magFilter               = VK_FILTER_NEAREST;
5074                     createInfo.minFilter               = VK_FILTER_NEAREST;
5075                     createInfo.mipmapMode              = VK_SAMPLER_MIPMAP_MODE_NEAREST;
5076                     createInfo.addressModeU            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5077                     createInfo.addressModeV            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5078                     createInfo.addressModeW            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5079                     createInfo.mipLodBias              = 0.0f;
5080                     createInfo.anisotropyEnable        = VK_FALSE;
5081                     createInfo.maxAnisotropy           = 1.0f;
5082                     createInfo.compareEnable           = VK_FALSE;
5083                     createInfo.compareOp               = VK_COMPARE_OP_NEVER;
5084                     createInfo.minLod                  = 0.0;
5085                     createInfo.maxLod                  = 0.0;
5086                     createInfo.borderColor             = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
5087                     createInfo.unnormalizedCoordinates = VK_FALSE;
5088 
5089                     VkSamplerCustomBorderColorCreateInfoEXT customBorderColorInfo = initVulkanStructure();
5090                     VkSamplerYcbcrConversionInfo samplerYcbcrConvInfo             = initVulkanStructure();
5091 
5092                     const void **nextPtr = &createInfo.pNext;
5093 
5094                     if (m_params.variant == TestVariant::YCBCR_SAMPLER)
5095                     {
5096                         createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5097                         createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5098                         createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5099 
5100                         samplerYcbcrConvInfo.conversion = *resources.samplerYcbcrConversion;
5101 
5102                         addToChainVulkanStructure(&nextPtr, samplerYcbcrConvInfo);
5103                     }
5104 
5105                     if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
5106                     {
5107                         createInfo.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT;
5108 
5109                         customBorderColorInfo.format            = VK_FORMAT_R32_UINT;
5110                         customBorderColorInfo.customBorderColor = makeClearValueColorU32(2, 0, 0, 1).color;
5111 
5112                         addToChainVulkanStructure(&nextPtr, customBorderColorInfo);
5113                     }
5114 
5115                     if (isCaptureDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER) ||
5116                         isCaptureDescriptor(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5117                     {
5118                         createInfo.flags |= VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
5119 
5120                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5121 
5122                         VkSamplerCaptureDescriptorDataInfoEXT info = initVulkanStructure();
5123                         info.sampler                               = *resources.sampler;
5124 
5125                         DE_ASSERT(captureReplayData.empty());
5126                         captureReplayData.resize(m_descriptorBufferProperties.samplerCaptureReplayDescriptorDataSize);
5127 
5128                         VK_CHECK(m_deviceInterface->getSamplerOpaqueCaptureDescriptorDataEXT(*m_device, &info,
5129                                                                                              captureReplayData.data()));
5130                     }
5131                     else if (isReplayDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER) ||
5132                              isReplayDescriptor(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5133                     {
5134                         reset(resources.sampler);
5135 
5136                         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
5137                         info.opaqueCaptureDescriptorData                = captureReplayData.data();
5138 
5139                         createInfo.flags |= VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
5140 
5141                         addToChainVulkanStructure(&nextPtr, info);
5142 
5143                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5144                     }
5145                     else if (m_testIteration == 0)
5146                     {
5147                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5148                     }
5149                 }
5150             }
5151         }
5152     }
5153 
5154     if ((m_params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS) ||
5155         (m_params.subcase == SubCase::IMMUTABLE_SAMPLERS) || (m_params.variant == TestVariant::YCBCR_SAMPLER))
5156     {
5157         // Patch immutable sampler pointers, now that all memory has been allocated and pointers won't move.
5158 
5159         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5160         {
5161             auto &dsl = **m_descriptorSetLayouts[setIndex];
5162 
5163             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5164             {
5165                 auto &binding = dsl.bindings[bindingIndex];
5166 
5167                 for (uint32_t resourceIndex = 0; resourceIndex < DE_LENGTH_OF_ARRAY(binding.perBindingResourceIndex);
5168                      ++resourceIndex)
5169                 {
5170                     if (binding.perBindingResourceIndex[resourceIndex] != INDEX_INVALID)
5171                     {
5172                         const auto &resources = **m_resources[binding.perBindingResourceIndex[resourceIndex]];
5173 
5174                         if (resources.sampler)
5175                         {
5176                             DE_ASSERT(resourceIndex < DE_LENGTH_OF_ARRAY(binding.immutableSamplers));
5177 
5178                             binding.immutableSamplers[resourceIndex] = *resources.sampler;
5179                         }
5180                     }
5181                 }
5182             }
5183         }
5184     }
5185 
5186     if (m_testIteration == 0)
5187     {
5188         createDescriptorSetLayouts();
5189         createDescriptorBuffers();
5190     }
5191 
5192     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5193     {
5194         auto &dsl = **m_descriptorSetLayouts[setIndex];
5195 
5196         if (dsl.hasEmbeddedImmutableSamplers)
5197         {
5198             // Embedded samplers are not written to the descriptor buffer directly.
5199             continue;
5200         }
5201 
5202         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5203         {
5204             auto &binding = dsl.bindings[bindingIndex];
5205 
5206             // The descriptor bindings are initialized in two situations:
5207             // 1. in the first test iteration (which is also the capture pass of capture/replay test)
5208             // 2. in the replay pass, for the binding with the matching descriptor type
5209             //
5210             if ((m_testIteration == 0) ||
5211                 (binding.isTestableDescriptor() && m_params.isCaptureReplayDescriptor(binding.descriptorType)))
5212             {
5213                 initializeBinding(dsl, setIndex, binding);
5214             }
5215         }
5216     }
5217 
5218     {
5219         VkPipelineLayoutCreateInfo createInfo = initVulkanStructure();
5220         const auto dslCopy                    = getDescriptorSetLayouts(m_descriptorSetLayouts);
5221         createInfo.setLayoutCount             = u32(dslCopy.size());
5222         createInfo.pSetLayouts                = dslCopy.data();
5223 
5224         m_pipelineLayout = createPipelineLayout(vk, *m_device, &createInfo);
5225     }
5226 
5227     if (m_params.isCompute())
5228     {
5229         const auto shaderModule = createShaderModule(vk, *m_device, getShaderBinary(VK_SHADER_STAGE_COMPUTE_BIT), 0u);
5230 
5231         const VkPipelineShaderStageCreateInfo pipelineShaderStageParams{
5232             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
5233             nullptr,                                             // const void* pNext;
5234             0u,                                                  // VkPipelineShaderStageCreateFlags flags;
5235             VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
5236             *shaderModule,                                       // VkShaderModule module;
5237             "main",                                              // const char* pName;
5238             nullptr,                                             // const VkSpecializationInfo* pSpecializationInfo;
5239         };
5240         VkComputePipelineCreateInfo pipelineCreateInfo{
5241             VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
5242             nullptr,                                        // const void* pNext;
5243             VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,   // VkPipelineCreateFlags flags;
5244             pipelineShaderStageParams,                      // VkPipelineShaderStageCreateInfo stage;
5245             *m_pipelineLayout,                              // VkPipelineLayout layout;
5246             DE_NULL,                                        // VkPipeline basePipelineHandle;
5247             0,                                              // int32_t basePipelineIndex;
5248         };
5249 
5250         vk::VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo = vk::initVulkanStructure();
5251         if (m_params.useMaintenance5)
5252         {
5253             pipelineFlags2CreateInfo.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT;
5254             pipelineCreateInfo.pNext       = &pipelineFlags2CreateInfo;
5255             pipelineCreateInfo.flags       = 0;
5256         }
5257 
5258         m_pipeline = createComputePipeline(vk, *m_device, DE_NULL, &pipelineCreateInfo);
5259     }
5260     else if (m_params.isRayTracing())
5261     {
5262         createRayTracingPipeline();
5263     }
5264     else
5265     {
5266         createGraphicsPipeline();
5267     }
5268 
5269     {
5270         auto cmdPool            = makeCommandPool(vk, *m_device, m_queueFamilyIndex);
5271         auto cmdBuf             = allocateCommandBuffer(vk, *m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
5272         const auto bindPoint    = m_params.isCompute()    ? VK_PIPELINE_BIND_POINT_COMPUTE :
5273                                   m_params.isRayTracing() ? VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR :
5274                                   m_params.isGraphics()   ? VK_PIPELINE_BIND_POINT_GRAPHICS :
5275                                                             VK_PIPELINE_BIND_POINT_MAX_ENUM;
5276         const auto dstStageMask = m_params.isCompute()    ? VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT :
5277                                   m_params.isRayTracing() ? VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR :
5278                                   m_params.isGraphics()   ? VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT :
5279                                                             VK_PIPELINE_STAGE_2_NONE;
5280         const auto dstStageMaskUp =
5281             m_params.isCompute()    ? VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT :
5282             m_params.isRayTracing() ? VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR :
5283             m_params.isGraphics()   ? VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT :
5284                                       VK_PIPELINE_STAGE_2_NONE;
5285 
5286         beginCommandBuffer(vk, *cmdBuf);
5287 
5288         vk.cmdBindPipeline(*cmdBuf, bindPoint, *m_pipeline);
5289 
5290         bindDescriptorBuffers(*cmdBuf, bindPoint);
5291 
5292         // Check if we need any staged descriptor set uploads or push descriptors.
5293 
5294         for (uint32_t setIndex = 0; setIndex < m_descriptorSetLayouts.size(); ++setIndex)
5295         {
5296             const auto &dsl = **m_descriptorSetLayouts[setIndex];
5297 
5298             if (dsl.usePushDescriptors)
5299             {
5300                 pushDescriptorSet(*cmdBuf, bindPoint, dsl, setIndex);
5301             }
5302             else if (dsl.stagingBufferOffset != OFFSET_UNUSED)
5303             {
5304                 VkBufferCopy copy{};
5305                 copy.srcOffset = dsl.stagingBufferOffset;
5306                 copy.dstOffset = dsl.bufferOffset;
5307                 copy.size      = dsl.sizeOfLayout;
5308 
5309                 VkBuffer descriptorBuffer = *m_descriptorBuffers[dsl.bufferIndex]->buffer;
5310 
5311                 vk.cmdCopyBuffer(*cmdBuf, *m_descriptorStagingBuffer.buffer, descriptorBuffer,
5312                                  1, // copy regions
5313                                  &copy);
5314 
5315                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5316                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_COPY_BIT;
5317                 barrier.srcAccessMask          = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5318                 barrier.dstStageMask           = dstStageMask;
5319                 barrier.dstAccessMask          = VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT;
5320                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5321                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5322                 barrier.buffer                 = descriptorBuffer;
5323                 barrier.offset                 = 0;
5324                 barrier.size                   = VK_WHOLE_SIZE;
5325 
5326                 VkDependencyInfo depInfo         = initVulkanStructure();
5327                 depInfo.bufferMemoryBarrierCount = 1;
5328                 depInfo.pBufferMemoryBarriers    = &barrier;
5329 
5330                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5331             }
5332         }
5333 
5334         // Upload image data
5335 
5336         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5337         {
5338             const auto &dsl = **m_descriptorSetLayouts[setIndex];
5339 
5340             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5341             {
5342                 const auto &binding = dsl.bindings[bindingIndex];
5343 
5344                 if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
5345                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
5346                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
5347                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5348                 {
5349                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
5350                     {
5351                         // Need to upload the image data from a staging buffer
5352                         const auto &dstImage  = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).image;
5353                         const auto &srcBuffer = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).buffer;
5354 
5355                         {
5356                             VkImageMemoryBarrier2 barrier = initVulkanStructure();
5357                             barrier.srcStageMask          = VK_PIPELINE_STAGE_2_NONE;
5358                             barrier.srcAccessMask         = VK_ACCESS_2_NONE;
5359                             barrier.dstStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5360                             barrier.dstAccessMask         = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5361                             barrier.oldLayout             = VK_IMAGE_LAYOUT_UNDEFINED;
5362                             barrier.newLayout             = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5363                             barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5364                             barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5365                             barrier.image                 = *dstImage.image;
5366                             barrier.subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5367 
5368                             VkDependencyInfo depInfo        = initVulkanStructure();
5369                             depInfo.imageMemoryBarrierCount = 1;
5370                             depInfo.pImageMemoryBarriers    = &barrier;
5371 
5372                             vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5373                         }
5374 
5375                         if (m_imageColorFormat == VK_FORMAT_R32_UINT)
5376                         {
5377                             VkBufferImageCopy region{};
5378                             // Use default buffer settings
5379                             region.imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1);
5380                             region.imageOffset      = makeOffset3D(0, 0, 0);
5381                             region.imageExtent = makeExtent3D(m_renderArea.extent.width, m_renderArea.extent.height, 1);
5382 
5383                             vk.cmdCopyBufferToImage(*cmdBuf, *srcBuffer.buffer, *dstImage.image,
5384                                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5385                                                     1, // region count
5386                                                     &region);
5387                         }
5388                         else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
5389                         {
5390                             std::vector<VkBufferImageCopy> regions(2);
5391 
5392                             regions[0].bufferOffset = 0;
5393                             regions[0].imageSubresource =
5394                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_PLANE_0_BIT, 0, 0, 1);
5395                             regions[0].imageOffset = makeOffset3D(0, 0, 0);
5396                             regions[0].imageExtent =
5397                                 makeExtent3D(m_renderArea.extent.width, m_renderArea.extent.height, 1);
5398 
5399                             regions[1].bufferOffset = m_renderArea.extent.width * m_renderArea.extent.height;
5400                             regions[1].imageSubresource =
5401                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_PLANE_1_BIT, 0, 0, 1);
5402                             regions[1].imageOffset = makeOffset3D(0, 0, 0);
5403                             regions[1].imageExtent =
5404                                 makeExtent3D(m_renderArea.extent.width / 2, m_renderArea.extent.height / 2, 1);
5405 
5406                             vk.cmdCopyBufferToImage(*cmdBuf, *srcBuffer.buffer, *dstImage.image,
5407                                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, u32(regions.size()),
5408                                                     regions.data());
5409                         }
5410                         else
5411                         {
5412                             DE_ASSERT(0);
5413                         }
5414 
5415                         {
5416                             VkImageMemoryBarrier2 barrier = initVulkanStructure();
5417                             barrier.srcStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5418                             barrier.srcAccessMask         = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5419                             barrier.dstStageMask          = dstStageMaskUp; // beginning of the shader pipeline
5420                             barrier.dstAccessMask         = VK_ACCESS_2_SHADER_READ_BIT;
5421                             barrier.oldLayout             = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5422                             barrier.newLayout             = dstImage.layout;
5423                             barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5424                             barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5425                             barrier.image                 = *dstImage.image;
5426                             barrier.subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5427 
5428                             VkDependencyInfo depInfo        = initVulkanStructure();
5429                             depInfo.imageMemoryBarrierCount = 1;
5430                             depInfo.pImageMemoryBarriers    = &barrier;
5431 
5432                             vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5433                         }
5434                     }
5435                 }
5436                 else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
5437                 {
5438                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
5439                     {
5440                         ResourceHolder &resource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]);
5441 
5442                         resource.rtBlas->build(*m_deviceInterface, *m_device, *cmdBuf);
5443                         resource.rtTlas->build(*m_deviceInterface, *m_device, *cmdBuf);
5444                     }
5445                 }
5446             }
5447         }
5448 
5449         if (m_params.isCompute())
5450         {
5451             vk.cmdDispatch(*cmdBuf, 1, 1, 1);
5452 
5453             {
5454                 auto &resultBuffer = getResultBuffer();
5455 
5456                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5457                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
5458                 barrier.srcAccessMask          = VK_ACCESS_2_SHADER_WRITE_BIT;
5459                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5460                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5461                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5462                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5463                 barrier.buffer                 = *resultBuffer.buffer;
5464                 barrier.offset                 = 0;
5465                 barrier.size                   = VK_WHOLE_SIZE;
5466 
5467                 VkDependencyInfo depInfo         = initVulkanStructure();
5468                 depInfo.bufferMemoryBarrierCount = 1;
5469                 depInfo.pBufferMemoryBarriers    = &barrier;
5470 
5471                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5472             }
5473         }
5474         else if (m_params.isRayTracing())
5475         {
5476             cmdTraceRays(vk, *cmdBuf, &m_raygenShaderBindingTableRegion, &m_missShaderBindingTableRegion,
5477                          &m_hitShaderBindingTableRegion, &m_callableShaderBindingTableRegion, 1, 1, 1);
5478 
5479             {
5480                 auto &resultBuffer = getResultBuffer();
5481 
5482                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5483                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR;
5484                 barrier.srcAccessMask          = VK_ACCESS_2_SHADER_WRITE_BIT;
5485                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5486                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5487                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5488                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5489                 barrier.buffer                 = *resultBuffer.buffer;
5490                 barrier.offset                 = 0;
5491                 barrier.size                   = VK_WHOLE_SIZE;
5492 
5493                 VkDependencyInfo depInfo         = initVulkanStructure();
5494                 depInfo.bufferMemoryBarrierCount = 1;
5495                 depInfo.pBufferMemoryBarriers    = &barrier;
5496 
5497                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5498             }
5499         }
5500         else
5501         {
5502             beginRenderPass(vk, *cmdBuf, *m_renderPass, *m_framebuffer, m_renderArea, tcu::Vec4());
5503 
5504             vk.cmdDraw(*cmdBuf, 6, 1, 0, 0);
5505 
5506             endRenderPass(vk, *cmdBuf);
5507 
5508             // Copy the rendered image to a host-visible buffer.
5509 
5510             {
5511                 VkImageMemoryBarrier2 barrier = initVulkanStructure();
5512                 barrier.srcStageMask          = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
5513                 barrier.srcAccessMask         = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
5514                 barrier.dstStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5515                 barrier.dstAccessMask         = VK_ACCESS_2_TRANSFER_READ_BIT;
5516                 barrier.oldLayout             = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5517                 barrier.newLayout             = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5518                 barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5519                 barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5520                 barrier.image                 = *m_colorImage.image;
5521                 barrier.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5522 
5523                 VkDependencyInfo depInfo        = initVulkanStructure();
5524                 depInfo.imageMemoryBarrierCount = 1;
5525                 depInfo.pImageMemoryBarriers    = &barrier;
5526 
5527                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5528             }
5529             {
5530                 VkBufferImageCopy region{};
5531                 // Use default buffer settings
5532                 region.imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1);
5533                 region.imageOffset      = makeOffset3D(0, 0, 0);
5534                 region.imageExtent      = m_colorImage.info.extent;
5535 
5536                 vk.cmdCopyImageToBuffer(*cmdBuf, *m_colorImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5537                                         *m_colorBuffer.buffer,
5538                                         1, // region count
5539                                         &region);
5540             }
5541             {
5542                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5543                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5544                 barrier.srcAccessMask          = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5545                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5546                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5547                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5548                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5549                 barrier.buffer                 = *m_colorBuffer.buffer;
5550                 barrier.offset                 = 0;
5551                 barrier.size                   = VK_WHOLE_SIZE;
5552 
5553                 VkDependencyInfo depInfo         = initVulkanStructure();
5554                 depInfo.bufferMemoryBarrierCount = 1;
5555                 depInfo.pBufferMemoryBarriers    = &barrier;
5556 
5557                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5558             }
5559         }
5560 
5561         endCommandBuffer(vk, *cmdBuf);
5562         submitCommandsAndWait(vk, *m_device, m_queue, *cmdBuf);
5563     }
5564 
5565     // Verification
5566     {
5567         const tcu::UVec4 *pResultData = nullptr;
5568 
5569         if (m_params.isCompute() || m_params.isRayTracing())
5570         {
5571             auto &resultBuffer = getResultBuffer();
5572 
5573             invalidateAlloc(vk, *m_device, *resultBuffer.alloc);
5574 
5575             pResultData = static_cast<const tcu::UVec4 *>(resultBuffer.alloc->getHostPtr());
5576         }
5577         else
5578         {
5579             pResultData = static_cast<const tcu::UVec4 *>(m_colorBuffer.alloc->getHostPtr());
5580         }
5581 
5582         const auto actual = pResultData->x();
5583         uint32_t expected = 0;
5584 
5585         for (const auto &sb : m_simpleBindings)
5586         {
5587             if (!(sb.isResultBuffer || sb.isRayTracingAS))
5588             {
5589                 if (m_params.variant == TestVariant::MAX)
5590                 {
5591                     // We test enough (image, sampler) pairs to access each one at least once.
5592                     expected = deMaxu32(m_params.samplerBufferBindingCount, m_params.resourceBufferBindingCount);
5593                 }
5594                 else
5595                 {
5596                     // Uniform blocks/buffers check 4 elements per iteration.
5597                     if (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
5598                     {
5599                         expected += ConstChecksPerBuffer * 4;
5600                     }
5601                     else if (sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
5602                     {
5603                         expected += ConstChecksPerBuffer * 4 * sb.count;
5604                     }
5605                     else if ((sb.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
5606                              (sb.type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ||
5607                              (sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER))
5608                     {
5609                         expected += ConstChecksPerBuffer * sb.count;
5610                     }
5611                     // Samplers are tested implicitly via sampled images
5612                     else if (sb.type != VK_DESCRIPTOR_TYPE_SAMPLER)
5613                     {
5614                         expected += sb.count;
5615                     }
5616                 }
5617             }
5618         }
5619 
5620         if (actual != expected)
5621         {
5622             uint32_t badSet        = 0;
5623             uint32_t badBinding    = 0;
5624             uint32_t badArrayIndex = 0;
5625 
5626             unpackBindingArgs(pResultData->y(), &badSet, &badBinding, &badArrayIndex);
5627 
5628             std::ostringstream msg;
5629             msg << "Wrong value in result buffer. Expected (" << expected << ") but got (" << actual << ").";
5630             msg << " The first wrong binding is (set = " << badSet << ", binding = " << badBinding << ")";
5631 
5632             if (m_params.variant == TestVariant::MAX)
5633             {
5634                 uint32_t badSamplerSet     = 0;
5635                 uint32_t badSamplerBinding = 0;
5636 
5637                 unpackBindingArgs(pResultData->z(), &badSamplerSet, &badSamplerBinding, nullptr);
5638 
5639                 msg << " which used a sampler (set = " << badSamplerSet << ", binding = " << badSamplerBinding << ")";
5640             }
5641             else if (badArrayIndex > 0)
5642             {
5643                 msg << " at array index " << badArrayIndex;
5644             }
5645 
5646             msg << ".";
5647 
5648             return tcu::TestStatus::fail(msg.str());
5649         }
5650     }
5651 
5652     if ((m_params.variant == TestVariant::CAPTURE_REPLAY) && (m_testIteration == 0))
5653     {
5654         // The first pass succeeded, continue to the next one where we verify replay.
5655         ++m_testIteration;
5656 
5657         return tcu::TestStatus::incomplete();
5658     }
5659 
5660     return tcu::TestStatus::pass("Pass");
5661 }
5662 
createInstance(Context & context) const5663 TestInstance *DescriptorBufferTestCase::createInstance(Context &context) const
5664 {
5665     // Currently all tests follow the same basic execution logic.
5666     return new DescriptorBufferTestInstance(context, m_params, m_simpleBindings);
5667 }
5668 
5669 // This simple tests verifies extension properties against the spec limits.
5670 //
testLimits(Context & context)5671 tcu::TestStatus testLimits(Context &context)
5672 {
5673 #define CHECK_MIN_LIMIT(_struct_, _field_, _limit_)               \
5674     if (_struct_._field_ < _limit_)                               \
5675     {                                                             \
5676         TCU_THROW(TestError, #_field_ " is less than " #_limit_); \
5677     }
5678 
5679 // Max implicitly checks nonzero too
5680 #define CHECK_MAX_LIMIT_NON_ZERO(_struct_, _field_, _limit_)         \
5681     if (_struct_._field_ == 0)                                       \
5682     {                                                                \
5683         TCU_THROW(TestError, #_field_ " is 0");                      \
5684     }                                                                \
5685     if (_struct_._field_ > _limit_)                                  \
5686     {                                                                \
5687         TCU_THROW(TestError, #_field_ " is greater than " #_limit_); \
5688     }
5689 
5690 #define CHECK_MAX_LIMIT(_struct_, _field_, _limit_)                  \
5691     if (_struct_._field_ > _limit_)                                  \
5692     {                                                                \
5693         TCU_THROW(TestError, #_field_ " is greater than " #_limit_); \
5694     }
5695 
5696     if (context.isDeviceFunctionalitySupported("VK_EXT_descriptor_buffer"))
5697     {
5698         const auto &features =
5699             *findStructure<VkPhysicalDeviceDescriptorBufferFeaturesEXT>(&context.getDeviceFeatures2());
5700         const auto &props =
5701             *findStructure<VkPhysicalDeviceDescriptorBufferPropertiesEXT>(&context.getDeviceProperties2());
5702         const bool hasRT = context.isDeviceFunctionalitySupported("VK_KHR_ray_tracing_pipeline") ||
5703                            context.isDeviceFunctionalitySupported("VK_KHR_ray_query");
5704         const size_t maxResourceDescriptorSize = std::max(
5705             props.storageImageDescriptorSize,
5706             std::max(props.sampledImageDescriptorSize,
5707                      std::max(props.robustUniformTexelBufferDescriptorSize,
5708                               std::max(props.robustStorageTexelBufferDescriptorSize,
5709                                        std::max(props.robustUniformBufferDescriptorSize,
5710                                                 std::max(props.robustStorageBufferDescriptorSize,
5711                                                          std::max(props.inputAttachmentDescriptorSize,
5712                                                                   std::max(props.accelerationStructureDescriptorSize,
5713                                                                            size_t(0u)))))))));
5714 
5715         DE_ASSERT(features.descriptorBuffer == VK_TRUE);
5716 
5717         // Must be queried directly from the physical device, the structure cached in the context has robustness disabled.
5718         VkPhysicalDeviceFeatures physDeviceFeatures{};
5719         context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &physDeviceFeatures);
5720 
5721         if (physDeviceFeatures.robustBufferAccess)
5722         {
5723             CHECK_MAX_LIMIT(props, robustUniformTexelBufferDescriptorSize, 256);
5724             CHECK_MAX_LIMIT(props, robustStorageTexelBufferDescriptorSize, 256);
5725             CHECK_MAX_LIMIT(props, robustUniformBufferDescriptorSize, 256);
5726             CHECK_MAX_LIMIT(props, robustStorageBufferDescriptorSize, 256);
5727         }
5728 
5729         if (features.descriptorBufferCaptureReplay)
5730         {
5731             CHECK_MAX_LIMIT(props, bufferCaptureReplayDescriptorDataSize, 64);
5732             CHECK_MAX_LIMIT(props, imageCaptureReplayDescriptorDataSize, 64);
5733             CHECK_MAX_LIMIT(props, imageViewCaptureReplayDescriptorDataSize, 64);
5734             CHECK_MAX_LIMIT(props, samplerCaptureReplayDescriptorDataSize, 64);
5735 
5736             if (hasRT)
5737             {
5738                 CHECK_MAX_LIMIT(props, accelerationStructureCaptureReplayDescriptorDataSize, 64);
5739             }
5740         }
5741 
5742         if (hasRT)
5743         {
5744             CHECK_MAX_LIMIT_NON_ZERO(props, accelerationStructureDescriptorSize, 256);
5745         }
5746 
5747         CHECK_MAX_LIMIT_NON_ZERO(props, descriptorBufferOffsetAlignment, 256);
5748 
5749         CHECK_MIN_LIMIT(props, maxDescriptorBufferBindings, 3);
5750         CHECK_MIN_LIMIT(props, maxResourceDescriptorBufferBindings, 1);
5751         CHECK_MIN_LIMIT(props, maxSamplerDescriptorBufferBindings, 1);
5752         CHECK_MIN_LIMIT(props, maxEmbeddedImmutableSamplerBindings, 1);
5753         CHECK_MIN_LIMIT(props, maxEmbeddedImmutableSamplers, 2032);
5754 
5755         CHECK_MAX_LIMIT_NON_ZERO(props, samplerDescriptorSize, 256);
5756         CHECK_MAX_LIMIT_NON_ZERO(props, combinedImageSamplerDescriptorSize, 256);
5757         CHECK_MAX_LIMIT_NON_ZERO(props, sampledImageDescriptorSize, 256);
5758         CHECK_MAX_LIMIT_NON_ZERO(props, storageImageDescriptorSize, 256);
5759         CHECK_MAX_LIMIT_NON_ZERO(props, uniformTexelBufferDescriptorSize, 256);
5760         CHECK_MAX_LIMIT_NON_ZERO(props, storageTexelBufferDescriptorSize, 256);
5761         CHECK_MAX_LIMIT_NON_ZERO(props, uniformBufferDescriptorSize, 256);
5762         CHECK_MAX_LIMIT_NON_ZERO(props, storageBufferDescriptorSize, 256);
5763         CHECK_MAX_LIMIT(props, inputAttachmentDescriptorSize, 256);
5764 
5765         CHECK_MIN_LIMIT(props, maxSamplerDescriptorBufferRange, ((1u << 11) * props.samplerDescriptorSize));
5766         CHECK_MIN_LIMIT(props, maxResourceDescriptorBufferRange,
5767                         (((1u << 20) - (1u << 15)) * maxResourceDescriptorSize));
5768         CHECK_MIN_LIMIT(props, samplerDescriptorBufferAddressSpaceSize, (1u << 27));
5769         CHECK_MIN_LIMIT(props, resourceDescriptorBufferAddressSpaceSize, (1u << 27));
5770         CHECK_MIN_LIMIT(props, descriptorBufferAddressSpaceSize, (1u << 27));
5771 
5772         // The following requirement ensures that for split combined image sampler arrays:
5773         // - there's no unnecessary padding at the end, or
5774         // - there's no risk of overrun (if somehow the sum of image and sampler was greater).
5775 
5776         if ((props.combinedImageSamplerDescriptorSingleArray == VK_FALSE) &&
5777             ((props.sampledImageDescriptorSize + props.samplerDescriptorSize) !=
5778              props.combinedImageSamplerDescriptorSize))
5779         {
5780             return tcu::TestStatus::fail(
5781                 "For combinedImageSamplerDescriptorSingleArray, it is expected that the sampled image size "
5782                 "and the sampler size add up to combinedImageSamplerDescriptorSize.");
5783         }
5784     }
5785     else
5786     {
5787         TCU_THROW(NotSupportedError, "VK_EXT_descriptor_buffer is not supported");
5788     }
5789 
5790     return tcu::TestStatus::pass("Pass");
5791 
5792 #undef CHECK_MIN_LIMIT
5793 #undef CHECK_MAX_LIMIT
5794 #undef CHECK_MAX_LIMIT_NON_ZERO
5795 }
5796 
populateDescriptorBufferTests(tcu::TestCaseGroup * topGroup)5797 void populateDescriptorBufferTests(tcu::TestCaseGroup *topGroup)
5798 {
5799     tcu::TestContext &testCtx = topGroup->getTestContext();
5800     const uint32_t baseSeed   = static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
5801     ;
5802     std::string caseName;
5803 
5804     const VkQueueFlagBits choiceQueues[]{
5805         VK_QUEUE_GRAPHICS_BIT,
5806         VK_QUEUE_COMPUTE_BIT,
5807     };
5808 
5809     const VkShaderStageFlagBits choiceStages[]{
5810         VK_SHADER_STAGE_VERTEX_BIT,
5811         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
5812         VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
5813         VK_SHADER_STAGE_GEOMETRY_BIT,
5814         VK_SHADER_STAGE_FRAGMENT_BIT,
5815         VK_SHADER_STAGE_COMPUTE_BIT,
5816         VK_SHADER_STAGE_RAYGEN_BIT_KHR,
5817         VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
5818         VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
5819         VK_SHADER_STAGE_MISS_BIT_KHR,
5820         VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
5821         VK_SHADER_STAGE_CALLABLE_BIT_KHR,
5822     };
5823 
5824     const bool choiceStagesCommands[]{
5825         false,
5826         true,
5827     };
5828 
5829     {
5830         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "basic"));
5831 
5832         addFunctionCase(subGroup.get(), "limits", testLimits);
5833 
5834         topGroup->addChild(subGroup.release());
5835     }
5836 
5837     {
5838         //
5839         // Basic single descriptor cases -- a quick check.
5840         //
5841         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "single"));
5842         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5843 
5844         // VK_DESCRIPTOR_TYPE_SAMPLER is tested implicitly by sampled image case.
5845         // *_BUFFER_DYNAMIC are not allowed with descriptor buffers.
5846         //
5847         const VkDescriptorType choiceDescriptors[]{
5848             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
5849             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,          VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
5850             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
5851             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,         VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
5852             VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,   VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
5853         };
5854 
5855         TestParams params{};
5856         params.variant            = TestVariant::SINGLE;
5857         params.subcase            = SubCase::NONE;
5858         params.bufferBindingCount = 1;
5859         params.setsPerBuffer      = 1;
5860         params.useMaintenance5    = false;
5861 
5862         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5863             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5864                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
5865                      ++pCommands2)
5866                     for (auto pDescriptor = choiceDescriptors; pDescriptor < DE_ARRAY_END(choiceDescriptors);
5867                          ++pDescriptor)
5868                     {
5869                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5870                         {
5871                             // Compute queue can only use compute shaders.
5872                             continue;
5873                         }
5874 
5875                         if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
5876                             (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
5877                         {
5878                             // Subpass loads are only valid in fragment stage.
5879                             continue;
5880                         }
5881 
5882                         params.stage      = *pStage;
5883                         params.queue      = *pQueue;
5884                         params.descriptor = *pDescriptor;
5885                         params.commands2  = *pCommands2;
5886 
5887                         subGroup->addChild(
5888                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5889                     }
5890 
5891         params.stage           = VK_SHADER_STAGE_COMPUTE_BIT;
5892         params.queue           = VK_QUEUE_COMPUTE_BIT;
5893         params.descriptor      = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
5894         params.useMaintenance5 = true;
5895 
5896         subGroup->addChild(new DescriptorBufferTestCase(testCtx, "compute_maintenance5", params));
5897         topGroup->addChild(subGroup.release());
5898     }
5899 
5900     {
5901         //
5902         // More complex cases. Multiple sets and bindings per buffer. Immutable samplers.
5903         //
5904         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "multiple"));
5905         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5906         const VkShaderStageFlags longTestStages =
5907             VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
5908 
5909         const struct
5910         {
5911             uint32_t bufferBindingCount;
5912             uint32_t setsPerBuffer;
5913         } caseOptions[] = {
5914             {1, 1}, {1, 3},  {2, 4},  {3, 1}, // 3 buffer bindings is spec minimum
5915             {8, 1}, {16, 1}, {32, 1},
5916         };
5917 
5918         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5919             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5920                 for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
5921                 {
5922                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5923                     {
5924                         // Compute queue can only use compute shaders.
5925                         continue;
5926                     }
5927 
5928                     if (pOptions->bufferBindingCount >= 16 && ((*pStage) & longTestStages) == 0)
5929                     {
5930                         // Allow long tests for certain stages only, skip on rest stages
5931                         continue;
5932                     }
5933 
5934                     TestParams params{};
5935                     params.variant                    = TestVariant::MULTIPLE;
5936                     params.subcase                    = SubCase::NONE;
5937                     params.stage                      = *pStage;
5938                     params.queue                      = *pQueue;
5939                     params.bufferBindingCount         = pOptions->bufferBindingCount;
5940                     params.samplerBufferBindingCount  = pOptions->bufferBindingCount;
5941                     params.resourceBufferBindingCount = pOptions->bufferBindingCount;
5942                     params.setsPerBuffer              = pOptions->setsPerBuffer;
5943                     params.descriptor =
5944                         VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; // Optional, will be tested if supported
5945                     params.useMaintenance5 = false;
5946 
5947                     subGroup->addChild(
5948                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5949 
5950                     if ((pOptions->setsPerBuffer != 1) && (pOptions->bufferBindingCount < 4))
5951                     {
5952                         // For the smaller binding counts add a subcase with immutable samplers.
5953 
5954                         params.subcase = SubCase::IMMUTABLE_SAMPLERS;
5955 
5956                         subGroup->addChild(
5957                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5958                     }
5959                 }
5960 
5961         topGroup->addChild(subGroup.release());
5962     }
5963 
5964     {
5965         //
5966         // These cases exercise buffers of single usage (samplers only and resources only) and tries to use
5967         // all available buffer bindings.
5968         //
5969         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "max"));
5970         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5971 
5972         const struct
5973         {
5974             uint32_t samplerBufferBindingCount;
5975             uint32_t resourceBufferBindingCount;
5976         } caseOptions[] = {
5977             {1, 1}, {2, 2}, {4, 4}, {8, 8}, {16, 16}, {1, 7}, {1, 15}, {1, 31}, {7, 1}, {15, 1}, {31, 1},
5978         };
5979 
5980         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5981             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5982                 for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
5983                 {
5984                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5985                     {
5986                         // Compute queue can only use compute shaders.
5987                         continue;
5988                     }
5989 
5990                     if (isAllRayTracingStages(*pStage) &&
5991                         (pOptions->samplerBufferBindingCount > 15 || pOptions->resourceBufferBindingCount > 15))
5992                     {
5993                         // Limit ray tracing stages
5994                         continue;
5995                     }
5996 
5997                     TestParams params{};
5998                     params.variant                    = TestVariant::MAX;
5999                     params.subcase                    = SubCase::NONE;
6000                     params.stage                      = *pStage;
6001                     params.queue                      = *pQueue;
6002                     params.samplerBufferBindingCount  = pOptions->samplerBufferBindingCount;
6003                     params.resourceBufferBindingCount = pOptions->resourceBufferBindingCount;
6004                     params.bufferBindingCount =
6005                         pOptions->samplerBufferBindingCount + pOptions->resourceBufferBindingCount;
6006                     params.setsPerBuffer   = 1;
6007                     params.descriptor      = VK_DESCRIPTOR_TYPE_MAX_ENUM;
6008                     params.useMaintenance5 = false;
6009 
6010                     subGroup->addChild(
6011                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6012                 }
6013 
6014         topGroup->addChild(subGroup.release());
6015     }
6016 
6017     {
6018         //
6019         // Check embedded immutable sampler buffers/bindings.
6020         //
6021         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "embedded_imm_samplers"));
6022         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6023 
6024         const struct
6025         {
6026             uint32_t bufferBindingCount;
6027             uint32_t samplersPerBuffer;
6028         } caseOptions[] = {
6029             {1, 1}, {1, 2}, {1, 4}, {1, 8}, {1, 16}, {2, 1}, {2, 2}, {3, 1}, {3, 3}, {8, 1}, {8, 4},
6030         };
6031 
6032         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6033             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6034                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
6035                      ++pCommands2)
6036                     for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
6037                     {
6038                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6039                         {
6040                             // Compute queue can only use compute shaders.
6041                             continue;
6042                         }
6043 
6044                         TestParams params{};
6045                         params.variant                                    = TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS;
6046                         params.subcase                                    = SubCase::NONE;
6047                         params.stage                                      = *pStage;
6048                         params.queue                                      = *pQueue;
6049                         params.bufferBindingCount                         = pOptions->bufferBindingCount + 1;
6050                         params.samplerBufferBindingCount                  = pOptions->bufferBindingCount;
6051                         params.resourceBufferBindingCount                 = 1;
6052                         params.setsPerBuffer                              = 1;
6053                         params.embeddedImmutableSamplerBufferBindingCount = pOptions->bufferBindingCount;
6054                         params.embeddedImmutableSamplersPerBuffer         = pOptions->samplersPerBuffer;
6055                         params.descriptor                                 = VK_DESCRIPTOR_TYPE_MAX_ENUM;
6056                         params.useMaintenance5                            = false;
6057                         params.commands2                                  = *pCommands2;
6058 
6059                         subGroup->addChild(
6060                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6061                     }
6062 
6063         topGroup->addChild(subGroup.release());
6064     }
6065 
6066     {
6067         //
6068         // Check push descriptors and push descriptors with template updates
6069         //
6070         MovePtr<tcu::TestCaseGroup> subGroupPush(new tcu::TestCaseGroup(testCtx, "push_descriptor"));
6071         MovePtr<tcu::TestCaseGroup> subGroupPushTemplate(new tcu::TestCaseGroup(testCtx, "push_template"));
6072         const uint32_t subGroupPushHash         = baseSeed ^ deStringHash(subGroupPush->getName());
6073         const uint32_t subGroupPushTemplateHash = baseSeed ^ deStringHash(subGroupPushTemplate->getName());
6074 
6075         const struct
6076         {
6077             uint32_t pushDescriptorSetIndex;
6078             uint32_t bufferBindingCount;
6079 
6080             // The total number of descriptor sets will be bufferBindingCount + 1, where the additional set is used for push descriptors.
6081 
6082         } caseOptions[] = {
6083             {0, 0}, // Only push descriptors
6084             {0, 1}, {0, 3}, {1, 1}, {0, 2},
6085             {1, 2}, {2, 2}, // index = 2 means 3 sets, where the first two are used with descriptor buffer and the last with push descriptors
6086             {3, 3},
6087         };
6088 
6089         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6090             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6091                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
6092                      ++pCommands2)
6093                     for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
6094                     {
6095                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6096                         {
6097                             // Compute queue can only use compute shaders.
6098                             continue;
6099                         }
6100 
6101                         TestParams params{};
6102                         params.variant                    = TestVariant::PUSH_DESCRIPTOR;
6103                         params.subcase                    = SubCase::NONE;
6104                         params.stage                      = *pStage;
6105                         params.queue                      = *pQueue;
6106                         params.bufferBindingCount         = pOptions->bufferBindingCount;
6107                         params.samplerBufferBindingCount  = pOptions->bufferBindingCount;
6108                         params.resourceBufferBindingCount = pOptions->bufferBindingCount;
6109                         params.setsPerBuffer              = 1;
6110                         params.pushDescriptorSetIndex     = pOptions->pushDescriptorSetIndex;
6111                         params.descriptor =
6112                             VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; // Optional, will be tested if supported
6113                         params.useMaintenance5 = false;
6114                         params.commands2       = *pCommands2;
6115 
6116                         subGroupPush->addChild(new DescriptorBufferTestCase(
6117                             testCtx, getCaseNameUpdateHash(params, subGroupPushHash), params));
6118 
6119                         if (pOptions->bufferBindingCount < 2)
6120                         {
6121                             TestParams paramsSingleBuffer = params;
6122 
6123                             paramsSingleBuffer.subcase = SubCase::SINGLE_BUFFER;
6124 
6125                             subGroupPush->addChild(new DescriptorBufferTestCase(
6126                                 testCtx, getCaseNameUpdateHash(paramsSingleBuffer, subGroupPushHash),
6127                                 paramsSingleBuffer));
6128                         }
6129 
6130                         params.variant = TestVariant::PUSH_TEMPLATE;
6131 
6132                         subGroupPushTemplate->addChild(new DescriptorBufferTestCase(
6133                             testCtx, getCaseNameUpdateHash(params, subGroupPushTemplateHash), params));
6134                     }
6135 
6136         topGroup->addChild(subGroupPush.release());
6137         topGroup->addChild(subGroupPushTemplate.release());
6138     }
6139 
6140     {
6141         //
6142         // Robustness tests
6143         //
6144         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "robust"));
6145         MovePtr<tcu::TestCaseGroup> subGroupBuffer(new tcu::TestCaseGroup(testCtx, "buffer_access"));
6146         MovePtr<tcu::TestCaseGroup> subGroupNullDescriptor(new tcu::TestCaseGroup(testCtx, "null_descriptor"));
6147         const uint32_t subGroupBufferHash         = baseSeed ^ deStringHash(subGroupBuffer->getName());
6148         const uint32_t subGroupNullDescriptorHash = baseSeed ^ deStringHash(subGroupNullDescriptor->getName());
6149 
6150         // Robust buffer access:
6151         // This test will fill the buffers with zeros and always expect to read zero values back (in and out of bounds).
6152 
6153         // Null descriptor cases:
6154         // For each test, one of these descriptors will have its buffer/imageView/etc. set to null handle.
6155         // Reads done through a null descriptor are expected to return zeros.
6156         //
6157         const VkDescriptorType choiceNullDescriptors[]{
6158             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
6159             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,          VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
6160             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
6161             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,         VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
6162         };
6163 
6164         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6165             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6166             {
6167                 if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6168                 {
6169                     // Compute queue can only use compute shaders.
6170                     continue;
6171                 }
6172 
6173                 TestParams params{};
6174                 params.variant            = TestVariant::ROBUST_BUFFER_ACCESS;
6175                 params.stage              = *pStage;
6176                 params.queue              = *pQueue;
6177                 params.bufferBindingCount = 1;
6178                 params.setsPerBuffer      = 1;
6179                 params.useMaintenance5    = false;
6180 
6181                 subGroupBuffer->addChild(
6182                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupBufferHash), params));
6183 
6184                 for (auto pDescriptor = choiceNullDescriptors; pDescriptor < DE_ARRAY_END(choiceNullDescriptors);
6185                      ++pDescriptor)
6186                 {
6187                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
6188                         (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
6189                     {
6190                         // Subpass loads are only valid in fragment stage.
6191                         continue;
6192                     }
6193 
6194                     params.variant    = TestVariant::ROBUST_NULL_DESCRIPTOR;
6195                     params.descriptor = *pDescriptor;
6196 
6197                     subGroupNullDescriptor->addChild(new DescriptorBufferTestCase(
6198                         testCtx, getCaseNameUpdateHash(params, subGroupNullDescriptorHash), params));
6199                 }
6200             }
6201 
6202         subGroup->addChild(subGroupBuffer.release());
6203         subGroup->addChild(subGroupNullDescriptor.release());
6204         topGroup->addChild(subGroup.release());
6205     }
6206 
6207     {
6208         //
6209         // Capture and replay
6210         //
6211         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "capture_replay"));
6212         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6213 
6214         const VkDescriptorType choiceDescriptors[]{
6215             VK_DESCRIPTOR_TYPE_SAMPLER,
6216             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // both sampler and image are captured
6217             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
6218             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6219             VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
6220             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6221             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
6222             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
6223             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
6224             VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
6225         };
6226 
6227         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6228             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6229                 for (auto pDescriptor = choiceDescriptors; pDescriptor < DE_ARRAY_END(choiceDescriptors); ++pDescriptor)
6230                 {
6231                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6232                     {
6233                         // Compute queue can only use compute shaders.
6234                         continue;
6235                     }
6236 
6237                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
6238                         (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
6239                     {
6240                         // Subpass loads are only valid in fragment stage.
6241                         continue;
6242                     }
6243 
6244                     TestParams params{};
6245                     params.variant            = TestVariant::CAPTURE_REPLAY;
6246                     params.subcase            = SubCase::NONE;
6247                     params.stage              = *pStage;
6248                     params.queue              = *pQueue;
6249                     params.descriptor         = *pDescriptor;
6250                     params.bufferBindingCount = 1;
6251                     params.setsPerBuffer      = 1;
6252                     params.useMaintenance5    = false;
6253 
6254                     subGroup->addChild(
6255                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6256 
6257                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
6258                         (*pDescriptor == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
6259                         (*pDescriptor == VK_DESCRIPTOR_TYPE_SAMPLER))
6260                     {
6261                         params.subcase = SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR;
6262 
6263                         subGroup->addChild(
6264                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6265                     }
6266                 }
6267 
6268         topGroup->addChild(subGroup.release());
6269     }
6270 
6271     {
6272         //
6273         // VK_EXT_mutable_descriptor_type tests
6274         //
6275         // Similar to multiple test case, but with mutable descriptor type instead.
6276         // Rather than using mutable type for everything, there are a few subcases that determine which descriptor
6277         // types can be replaced with the mutable type.
6278         //
6279         MovePtr<tcu::TestCaseGroup> subGroup(
6280             new tcu::TestCaseGroup(testCtx, "mutable_descriptor", "Mutable descriptor type tests"));
6281         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6282 
6283         const DescriptorMask choiceDescriptorMasks[]{
6284             // Single
6285             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER}),
6286             makeDescriptorMask({VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6287             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}),
6288             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6289             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER}),
6290             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER}),
6291             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER}),
6292             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6293             makeDescriptorMask({VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6294 
6295             // Multiple - images/samplers
6296             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6297             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6298             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6299             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6300             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6301                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6302             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6303                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6304                                 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6305 
6306             // Multiple - buffers
6307             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER}),
6308             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6309             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6310                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6311 
6312             // Everything
6313             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6314                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6315                                 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6316                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6317             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6318                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6319                                 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6320                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
6321                                 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}), // with input attachment
6322         };
6323 
6324         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6325             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6326                 for (auto pMask = choiceDescriptorMasks; pMask < DE_ARRAY_END(choiceDescriptorMasks); ++pMask)
6327                 {
6328                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6329                     {
6330                         // Compute queue can only use compute shaders.
6331                         continue;
6332                     }
6333 
6334                     if ((*pStage != VK_SHADER_STAGE_FRAGMENT_BIT) &&
6335                         (maskCheck(*pMask, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)))
6336                     {
6337                         // Subpass loads are only valid in fragment stage.
6338                         continue;
6339                     }
6340 
6341                     TestParams params{};
6342                     params.variant                = TestVariant::MUTABLE_DESCRIPTOR_TYPE;
6343                     params.stage                  = *pStage;
6344                     params.queue                  = *pQueue;
6345                     params.bufferBindingCount     = 1;
6346                     params.setsPerBuffer          = 1;
6347                     params.mutableDescriptorTypes = *pMask;
6348 
6349                     subGroup->addChild(
6350                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6351                 }
6352 
6353         topGroup->addChild(subGroup.release());
6354     }
6355 
6356     {
6357         //
6358         // ycbcr sampler conversion interaction
6359         //
6360         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "ycbcr_sampler", "ycbcr sampler tests"));
6361         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6362 
6363         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6364             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6365             {
6366                 if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6367                 {
6368                     // Compute queue can only use compute shaders.
6369                     continue;
6370                 }
6371 
6372                 TestParams params{};
6373                 params.variant            = TestVariant::YCBCR_SAMPLER;
6374                 params.subcase            = SubCase::NONE;
6375                 params.stage              = *pStage;
6376                 params.queue              = *pQueue;
6377                 params.descriptor         = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6378                 params.bufferBindingCount = 1;
6379                 params.setsPerBuffer      = 1;
6380 
6381                 subGroup->addChild(
6382                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6383 
6384                 params.subcase = SubCase::YCBCR_SAMPLER_ARRAY;
6385 
6386                 subGroup->addChild(
6387                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6388             }
6389 
6390         topGroup->addChild(subGroup.release());
6391     }
6392 }
6393 
6394 } // namespace
6395 
createDescriptorBufferTests(tcu::TestContext & testCtx)6396 tcu::TestCaseGroup *createDescriptorBufferTests(tcu::TestContext &testCtx)
6397 {
6398     return createTestGroup(testCtx, "descriptor_buffer", populateDescriptorBufferTests);
6399 }
6400 
6401 } // namespace BindingModel
6402 } // namespace vkt
6403