• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon017810290111::TestParams370     bool isCompute() const
371     {
372         return stage == VK_SHADER_STAGE_COMPUTE_BIT;
373     }
374 
isGraphicsvkt::BindingModel::__anon017810290111::TestParams375     bool isGraphics() const
376     {
377         return (stage & VK_SHADER_STAGE_ALL_GRAPHICS) != 0;
378     }
379 
isGeometryvkt::BindingModel::__anon017810290111::TestParams380     bool isGeometry() const
381     {
382         return stage == VK_SHADER_STAGE_GEOMETRY_BIT;
383     }
384 
isTessellationvkt::BindingModel::__anon017810290111::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::__anon017810290111::TestParams390     bool isPushDescriptorTest() const
391     {
392         return (variant == TestVariant::PUSH_DESCRIPTOR) || (variant == TestVariant::PUSH_TEMPLATE);
393     }
394 
isAccelerationStructurevkt::BindingModel::__anon017810290111::TestParams395     bool isAccelerationStructure() const
396     {
397         return descriptor == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
398     }
399 
isRayTracingvkt::BindingModel::__anon017810290111::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::__anon017810290111::TestParams406     bool isCaptureReplayDescriptor(VkDescriptorType otherType) const
407     {
408         return (variant == TestVariant::CAPTURE_REPLAY) && (descriptor == otherType);
409     }
410 
isAccelerationStructureOptionalvkt::BindingModel::__anon017810290111::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::__anon017810290111::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::__anon017810290111::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::__anon017810290111::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 
addDescriptorSetLayout()2514     uint32_t addDescriptorSetLayout()
2515     {
2516         m_descriptorSetLayouts.emplace_back(makeSharedUniquePtr<DescriptorSetLayoutHolder>());
2517         return u32(m_descriptorSetLayouts.size()) - 1;
2518     }
2519 
2520     // The resources used by descriptors are tracked in a simple array and referenced by an index.
addResource()2521     uint32_t addResource()
2522     {
2523         m_resources.emplace_back(makeSharedUniquePtr<ResourceHolder>());
2524         return u32(m_resources.size()) - 1;
2525     }
2526 
getOrCreateResource(Binding & binding,uint32_t arrayIndex)2527     ResourceHolder &getOrCreateResource(Binding &binding, uint32_t arrayIndex)
2528     {
2529         if (binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID)
2530         {
2531             binding.perBindingResourceIndex[arrayIndex] = addResource();
2532         }
2533 
2534         ResourceHolder &result = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]);
2535 
2536         return result;
2537     }
2538 
getShaderName(const VkShaderStageFlagBits stage) const2539     const std::string getShaderName(const VkShaderStageFlagBits stage) const
2540     {
2541         return toString(stage) + (m_params.isAccelerationStructure() && (m_params.stage == stage) ? "_as" : "");
2542     }
2543 
getShaderBinary(const VkShaderStageFlagBits stage) const2544     const ProgramBinary &getShaderBinary(const VkShaderStageFlagBits stage) const
2545     {
2546         return m_context.getBinaryCollection().get(getShaderName(stage));
2547     }
2548 
isCaptureDescriptor(VkDescriptorType type) const2549     bool isCaptureDescriptor(VkDescriptorType type) const
2550     {
2551         return (m_testIteration == 0) && m_params.isCaptureReplayDescriptor(type);
2552     }
2553 
isReplayDescriptor(VkDescriptorType type) const2554     bool isReplayDescriptor(VkDescriptorType type) const
2555     {
2556         return (m_testIteration == 1) && m_params.isCaptureReplayDescriptor(type);
2557     }
2558 
2559     // Test cases using compute shaders always declare one binding with a result buffer.
getResultBuffer() const2560     const BufferAlloc &getResultBuffer() const
2561     {
2562         DE_ASSERT(m_params.isCompute() || m_params.isRayTracing());
2563 
2564         const uint32_t resultBufferIndex = getResultBufferIndex(m_simpleBindings);
2565         DE_ASSERT(resultBufferIndex != INDEX_INVALID);
2566         const auto &sb = m_simpleBindings[resultBufferIndex];
2567 
2568         const auto binding = std::find_if((**m_descriptorSetLayouts[sb.set]).bindings.begin(),
2569                                           (**m_descriptorSetLayouts[sb.set]).bindings.end(),
2570                                           [&sb](const Binding &it) { return it.binding == sb.binding; });
2571 
2572         DE_ASSERT(binding->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
2573 
2574         // There's only one result buffer at this binding
2575         return (**m_resources[binding->perBindingResourceIndex[0]]).buffer;
2576     }
2577 
2578 protected:
2579     TestParams m_params;
2580     std::vector<SimpleBinding> m_simpleBindings;
2581 
2582     Move<VkDevice> m_device;
2583     MovePtr<DeviceDriver> m_deviceInterface;
2584     VkQueue m_queue;
2585     uint32_t m_queueFamilyIndex;
2586     MovePtr<Allocator> m_allocatorPtr;
2587 
2588     VkPhysicalDeviceMemoryProperties m_memoryProperties;
2589     VkPhysicalDeviceDescriptorBufferFeaturesEXT m_descriptorBufferFeatures;
2590     VkPhysicalDeviceDescriptorBufferPropertiesEXT m_descriptorBufferProperties;
2591 
2592     Move<VkPipeline> m_pipeline;
2593     Move<VkPipelineLayout> m_pipelineLayout;
2594 
2595     // Optional, for graphics pipelines
2596     Move<VkFramebuffer> m_framebuffer;
2597     Move<VkRenderPass> m_renderPass;
2598     VkRect2D m_renderArea;
2599     ImageAlloc m_colorImage;
2600     BufferAlloc m_colorBuffer; // for copying back to host visible memory
2601 
2602     std::vector<DSLPtr> m_descriptorSetLayouts;
2603     std::vector<BufferAllocPtr> m_descriptorBuffers;
2604     BufferAlloc m_descriptorStagingBuffer;
2605 
2606     // Ray Tracing fields
2607     uint32_t m_shaders;
2608     uint32_t m_raygenShaderGroup;
2609     uint32_t m_missShaderGroup;
2610     uint32_t m_hitShaderGroup;
2611     uint32_t m_callableShaderGroup;
2612     uint32_t m_shaderGroupCount;
2613 
2614     de::MovePtr<RayTracingPipeline> m_rayTracingPipeline;
2615 
2616     de::MovePtr<BufferWithMemory> m_raygenShaderBindingTable;
2617     de::MovePtr<BufferWithMemory> m_hitShaderBindingTable;
2618     de::MovePtr<BufferWithMemory> m_missShaderBindingTable;
2619     de::MovePtr<BufferWithMemory> m_callableShaderBindingTable;
2620 
2621     VkStridedDeviceAddressRegionKHR m_raygenShaderBindingTableRegion;
2622     VkStridedDeviceAddressRegionKHR m_missShaderBindingTableRegion;
2623     VkStridedDeviceAddressRegionKHR m_hitShaderBindingTableRegion;
2624     VkStridedDeviceAddressRegionKHR m_callableShaderBindingTableRegion;
2625 
2626     de::SharedPtr<BottomLevelAccelerationStructure> m_bottomLevelAccelerationStructure;
2627     de::SharedPtr<TopLevelAccelerationStructure> m_topLevelAccelerationStructure;
2628 
2629     // Optional, ycbcr conversion test
2630     VkFormat m_imageColorFormat;
2631     uint32_t m_combinedImageSamplerDescriptorCount;
2632 
2633     // Common, but last
2634     std::vector<ResourcePtr> m_resources; // various resources used to test the descriptors
2635     uint32_t m_testIteration;             // for multi-pass tests such as capture/replay
2636 };
2637 
DescriptorBufferTestInstance(Context & context,const TestParams & params,const std::vector<SimpleBinding> & simpleBindings)2638 DescriptorBufferTestInstance::DescriptorBufferTestInstance(Context &context, const TestParams &params,
2639                                                            const std::vector<SimpleBinding> &simpleBindings)
2640     : TestInstance(context)
2641     , m_params(params)
2642     , m_simpleBindings(simpleBindings)
2643     , m_device()
2644     , m_deviceInterface()
2645     , m_queue()
2646     , m_queueFamilyIndex()
2647     , m_allocatorPtr(DE_NULL)
2648     , m_memoryProperties()
2649     , m_descriptorBufferFeatures()
2650     , m_descriptorBufferProperties()
2651     , m_pipeline()
2652     , m_pipelineLayout()
2653     , m_framebuffer()
2654     , m_renderPass()
2655     , m_renderArea(makeRect2D(0, 0, 4, 2)) // 4x2 to support _420 format, if needed
2656     , m_colorImage()
2657     , m_colorBuffer()
2658     , m_descriptorSetLayouts()
2659     , m_descriptorBuffers()
2660     , m_descriptorStagingBuffer()
2661     , m_shaders(0)
2662     , m_raygenShaderGroup(~0u)
2663     , m_missShaderGroup(~0u)
2664     , m_hitShaderGroup(~0u)
2665     , m_callableShaderGroup(~0u)
2666     , m_shaderGroupCount(0)
2667     , m_rayTracingPipeline(DE_NULL)
2668     , m_raygenShaderBindingTable()
2669     , m_hitShaderBindingTable()
2670     , m_missShaderBindingTable()
2671     , m_callableShaderBindingTable()
2672     , m_raygenShaderBindingTableRegion()
2673     , m_missShaderBindingTableRegion()
2674     , m_hitShaderBindingTableRegion()
2675     , m_callableShaderBindingTableRegion()
2676     , m_bottomLevelAccelerationStructure()
2677     , m_topLevelAccelerationStructure()
2678     , m_imageColorFormat()
2679     , m_combinedImageSamplerDescriptorCount(1)
2680     , m_resources()
2681     , m_testIteration(0)
2682 {
2683     // Need to create a new device because:
2684     // - We want to test graphics and compute queues,
2685     // - We must exclude VK_AMD_shader_fragment_mask from the enabled extensions.
2686 
2687     if (m_params.isAccelerationStructure() && m_params.isAccelerationStructureOptional())
2688     {
2689         if (!m_context.getRayQueryFeatures().rayQuery)
2690         {
2691             // Disable testing of acceleration structures if they ray query is not supported
2692             m_params.descriptor = VK_DESCRIPTOR_TYPE_MAX_ENUM;
2693 
2694             // Replace acceleration structures with storage buffers
2695             for (auto &simpleBinding : m_simpleBindings)
2696                 if ((simpleBinding.type == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR) &&
2697                     !simpleBinding.isRayTracingAS)
2698                     simpleBinding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
2699         }
2700         else
2701         {
2702             context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2703         }
2704     }
2705 
2706     if ((m_params.variant == TestVariant::MULTIPLE) || (m_params.variant == TestVariant::PUSH_DESCRIPTOR) ||
2707         (m_params.variant == TestVariant::PUSH_TEMPLATE) || (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS) ||
2708         (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR))
2709     {
2710         const vk::VkPhysicalDeviceLimits &limits = context.getDeviceProperties().limits;
2711         uint32_t maxPerStageDescriptorSamplers =
2712             0; // VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
2713         uint32_t maxPerStageDescriptorUniformBuffers = 0; // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
2714         uint32_t maxPerStageDescriptorStorageBuffers = 0; // VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
2715         uint32_t maxPerStageDescriptorSampledImages =
2716             0; // VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, or VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
2717         uint32_t maxPerStageDescriptorStorageImages =
2718             0; // VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
2719         uint32_t maxPerStageDescriptorInputAttachments = 0; // VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
2720 
2721         for (const auto &simpleBinding : m_simpleBindings)
2722         {
2723             switch (simpleBinding.type)
2724             {
2725             case VK_DESCRIPTOR_TYPE_SAMPLER:
2726                 maxPerStageDescriptorSamplers += simpleBinding.count;
2727                 break;
2728             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2729                 maxPerStageDescriptorSamplers += simpleBinding.count;
2730                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2731                 break;
2732             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2733                 maxPerStageDescriptorUniformBuffers += simpleBinding.count;
2734                 break;
2735             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2736                 maxPerStageDescriptorStorageBuffers += simpleBinding.count;
2737                 break;
2738             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2739                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2740                 break;
2741             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2742                 maxPerStageDescriptorSampledImages += simpleBinding.count;
2743                 break;
2744             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2745                 maxPerStageDescriptorStorageImages += simpleBinding.count;
2746                 break;
2747             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2748                 maxPerStageDescriptorStorageImages += simpleBinding.count;
2749                 break;
2750             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2751                 maxPerStageDescriptorInputAttachments += simpleBinding.count;
2752                 break;
2753             default:
2754                 break;
2755             }
2756         }
2757 
2758 #define VALIDATE_PER_STAGE_LIMIT(NAME)                                                                           \
2759     if (NAME > limits.NAME)                                                                                      \
2760         TCU_THROW(NotSupportedError, std::string(#NAME) + " " + de::toString(NAME) + " is greater than limit " + \
2761                                          de::toString(limits.NAME));
2762         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorSamplers);
2763         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorUniformBuffers);
2764         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorStorageBuffers);
2765         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorSampledImages);
2766         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorStorageImages);
2767         VALIDATE_PER_STAGE_LIMIT(maxPerStageDescriptorInputAttachments);
2768 #undef VALIDATE_PER_STAGE_LIMIT
2769     }
2770 
2771     auto &inst      = context.getInstanceInterface();
2772     auto physDevice = context.getPhysicalDevice();
2773     auto queueProps = getPhysicalDeviceQueueFamilyProperties(inst, physDevice);
2774 
2775     m_queueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
2776 
2777     uint32_t graphicsComputeQueue = VK_QUEUE_FAMILY_IGNORED;
2778 
2779     for (uint32_t i = 0; i < queueProps.size(); ++i)
2780     {
2781         if (m_params.queue == VK_QUEUE_GRAPHICS_BIT)
2782         {
2783             if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
2784             {
2785                 m_queueFamilyIndex = i;
2786 
2787                 break;
2788             }
2789         }
2790         else if (m_params.queue == VK_QUEUE_COMPUTE_BIT)
2791         {
2792             if (((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) &&
2793                 ((queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0))
2794             {
2795                 m_queueFamilyIndex = i;
2796             }
2797             else if (((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) &&
2798                      ((queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) != 0))
2799             {
2800                 graphicsComputeQueue = i;
2801             }
2802         }
2803     }
2804 
2805     // If a compute only queue could not be found, fall back to a
2806     // graphics & compute one.
2807     if (m_params.queue == VK_QUEUE_COMPUTE_BIT && m_queueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
2808     {
2809         m_queueFamilyIndex = graphicsComputeQueue;
2810     }
2811 
2812     if (m_queueFamilyIndex == VK_QUEUE_FAMILY_IGNORED)
2813     {
2814         TCU_THROW(NotSupportedError, "Queue not supported");
2815     }
2816 
2817     const float priority[1] = {0.5f};
2818 
2819     VkDeviceQueueCreateInfo queueInfo = initVulkanStructure();
2820     queueInfo.queueFamilyIndex        = m_queueFamilyIndex;
2821     queueInfo.queueCount              = 1;
2822     queueInfo.pQueuePriorities        = priority;
2823 
2824     VkPhysicalDeviceFeatures2 features2                                            = initVulkanStructure();
2825     VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufferFeatures           = initVulkanStructure();
2826     VkPhysicalDeviceInlineUniformBlockFeaturesEXT inlineUniformBlockFeatures       = initVulkanStructure();
2827     VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features           = initVulkanStructure();
2828     VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features                     = initVulkanStructure();
2829     VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutableDescTypeFeatures       = initVulkanStructure();
2830     VkPhysicalDeviceCustomBorderColorFeaturesEXT customBorderColorFeatures         = initVulkanStructure();
2831     VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR samplerYcbcrConvFeatures     = initVulkanStructure();
2832     VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures = initVulkanStructure();
2833     VkPhysicalDeviceRayQueryFeaturesKHR rayQueryFeatures                           = initVulkanStructure();
2834     VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures       = initVulkanStructure();
2835     VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddressFeatures        = initVulkanStructure();
2836     VkPhysicalDeviceMaintenance4Features maintenance4Features                      = initVulkanStructure();
2837     VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5Features                   = initVulkanStructure();
2838     VkPhysicalDeviceMaintenance6FeaturesKHR maintenance6Features                   = initVulkanStructure();
2839 
2840     void **nextPtr = &features2.pNext;
2841     addToChainVulkanStructure(&nextPtr, synchronization2Features);
2842     addToChainVulkanStructure(&nextPtr, descriptorBufferFeatures);
2843     addToChainVulkanStructure(&nextPtr, bufferDeviceAddressFeatures);
2844     addToChainVulkanStructure(&nextPtr, maintenance4Features);
2845 
2846     // NOTE: VK_AMD_shader_fragment_mask must not be enabled
2847     std::vector<const char *> extensions;
2848     extensions.push_back("VK_EXT_descriptor_buffer");
2849     extensions.push_back("VK_KHR_buffer_device_address");
2850     extensions.push_back("VK_KHR_synchronization2");
2851     extensions.push_back("VK_EXT_descriptor_indexing");
2852     extensions.push_back("VK_KHR_maintenance4");
2853 
2854     if (m_params.useMaintenance5)
2855     {
2856         addToChainVulkanStructure(&nextPtr, maintenance5Features);
2857         extensions.push_back("VK_KHR_maintenance5");
2858     }
2859 
2860     if ((m_params.descriptor == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ||
2861         (m_params.variant == TestVariant::MULTIPLE) || m_params.isPushDescriptorTest())
2862     {
2863         extensions.push_back("VK_EXT_inline_uniform_block");
2864         addToChainVulkanStructure(&nextPtr, inlineUniformBlockFeatures);
2865 
2866         if (m_params.isPushDescriptorTest())
2867             extensions.push_back("VK_KHR_push_descriptor");
2868     }
2869     else if (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR ||
2870              m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS)
2871     {
2872         if (context.isDeviceFunctionalitySupported("VK_EXT_robustness2"))
2873         {
2874             extensions.push_back("VK_EXT_robustness2");
2875             addToChainVulkanStructure(&nextPtr, robustness2Features);
2876         }
2877     }
2878     else if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
2879     {
2880         extensions.push_back("VK_EXT_custom_border_color");
2881         addToChainVulkanStructure(&nextPtr, customBorderColorFeatures);
2882     }
2883     else if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
2884     {
2885         extensions.push_back("VK_EXT_mutable_descriptor_type");
2886         addToChainVulkanStructure(&nextPtr, mutableDescTypeFeatures);
2887     }
2888     else if (m_params.variant == TestVariant::YCBCR_SAMPLER)
2889     {
2890         extensions.push_back("VK_KHR_sampler_ycbcr_conversion");
2891         addToChainVulkanStructure(&nextPtr, samplerYcbcrConvFeatures);
2892     }
2893 
2894     if (m_params.isAccelerationStructure() || m_params.isRayTracing())
2895     {
2896         extensions.push_back("VK_KHR_acceleration_structure");
2897         addToChainVulkanStructure(&nextPtr, accelerationStructureFeatures);
2898         extensions.push_back("VK_KHR_spirv_1_4");
2899         extensions.push_back("VK_KHR_deferred_host_operations");
2900 
2901         if (m_params.isAccelerationStructure())
2902         {
2903             extensions.push_back("VK_KHR_ray_query");
2904             addToChainVulkanStructure(&nextPtr, rayQueryFeatures);
2905             extensions.push_back("VK_KHR_deferred_host_operations");
2906         }
2907 
2908         if (m_params.isRayTracing())
2909         {
2910             extensions.push_back("VK_KHR_ray_tracing_pipeline");
2911             addToChainVulkanStructure(&nextPtr, rayTracingPipelineFeatures);
2912         }
2913     }
2914 
2915     if (m_params.commands2)
2916     {
2917         extensions.push_back("VK_KHR_maintenance6");
2918         addToChainVulkanStructure(&nextPtr, maintenance6Features);
2919     }
2920 
2921     context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
2922 
2923     if (m_params.variant != TestVariant::ROBUST_BUFFER_ACCESS)
2924     {
2925         features2.features.robustBufferAccess   = VK_FALSE;
2926         robustness2Features.robustBufferAccess2 = VK_FALSE;
2927         robustness2Features.robustImageAccess2  = VK_FALSE;
2928     }
2929 
2930     if (m_params.variant != TestVariant::ROBUST_NULL_DESCRIPTOR)
2931     {
2932         robustness2Features.nullDescriptor = VK_FALSE;
2933     }
2934 
2935     if (!m_params.isPushDescriptorTest())
2936     {
2937         descriptorBufferFeatures.descriptorBufferPushDescriptors = VK_FALSE;
2938     }
2939 
2940     if (!maintenance4Features.maintenance4)
2941         TCU_THROW(NotSupportedError, "Execution mode LocalSizeId is used, maintenance4 required");
2942 
2943     if (m_params.isAccelerationStructure() || m_params.isRayTracing())
2944     {
2945         if (!accelerationStructureFeatures.accelerationStructure)
2946             TCU_THROW(NotSupportedError, "Require accelerationStructureFeatures.accelerationStructure");
2947 
2948         if (m_params.isCaptureReplayDescriptor(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR))
2949         {
2950             if (!accelerationStructureFeatures.accelerationStructureCaptureReplay)
2951                 TCU_THROW(NotSupportedError,
2952                           "Require accelerationStructureFeatures.accelerationStructureCaptureReplay");
2953         }
2954 
2955         if (m_params.isAccelerationStructure())
2956         {
2957             if (!rayQueryFeatures.rayQuery)
2958                 TCU_THROW(NotSupportedError, "Require rayQueryFeatures.rayQuery");
2959         }
2960 
2961         if (m_params.isRayTracing())
2962         {
2963             if (!rayTracingPipelineFeatures.rayTracingPipeline)
2964                 TCU_THROW(NotSupportedError, "Require rayTracingPipelineFeatures.rayTracingPipeline");
2965 
2966             if (m_params.isCaptureReplayDescriptor(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR))
2967             {
2968                 if (!rayTracingPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplay)
2969                     TCU_THROW(NotSupportedError,
2970                               "Require rayTracingPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplay");
2971             }
2972         }
2973     }
2974 
2975     if (m_params.commands2)
2976     {
2977         if (!maintenance6Features.maintenance6)
2978             TCU_THROW(NotSupportedError, "maintenance6 required");
2979     }
2980 
2981     // Should be enabled by default
2982     DE_ASSERT(descriptorBufferFeatures.descriptorBuffer);
2983     DE_ASSERT(synchronization2Features.synchronization2);
2984 
2985     if (m_params.variant == TestVariant::MULTIPLE || m_params.isPushDescriptorTest())
2986     {
2987         // TODO: Currently these tests assume the feature is available and there's no easy way to make it optional.
2988         // Rather than returning NotSupported, this should be reworked if many implementations have this limitation.
2989         DE_ASSERT(inlineUniformBlockFeatures.inlineUniformBlock);
2990     }
2991     else if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
2992     {
2993         DE_ASSERT(customBorderColorFeatures.customBorderColors);
2994     }
2995     else if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
2996     {
2997         DE_ASSERT(mutableDescTypeFeatures.mutableDescriptorType);
2998     }
2999     else if (params.variant == TestVariant::YCBCR_SAMPLER)
3000     {
3001         DE_ASSERT(samplerYcbcrConvFeatures.samplerYcbcrConversion);
3002     }
3003 
3004     m_descriptorBufferFeatures       = descriptorBufferFeatures;
3005     m_descriptorBufferFeatures.pNext = nullptr;
3006 
3007     m_descriptorBufferProperties =
3008         *findStructure<VkPhysicalDeviceDescriptorBufferPropertiesEXT>(&context.getDeviceProperties2());
3009     m_descriptorBufferProperties.pNext = nullptr;
3010 
3011     VkDeviceCreateInfo createInfo      = initVulkanStructure(&features2);
3012     createInfo.pEnabledFeatures        = DE_NULL;
3013     createInfo.enabledExtensionCount   = u32(extensions.size());
3014     createInfo.ppEnabledExtensionNames = extensions.data();
3015     createInfo.queueCreateInfoCount    = 1;
3016     createInfo.pQueueCreateInfos       = &queueInfo;
3017 
3018     m_device =
3019         createCustomDevice(false, context.getPlatformInterface(), context.getInstance(), inst, physDevice, &createInfo);
3020 
3021     context.getDeviceInterface().getDeviceQueue(*m_device, m_queueFamilyIndex, 0, &m_queue);
3022 
3023     m_deviceInterface =
3024         newMovePtr<DeviceDriver>(context.getPlatformInterface(), context.getInstance(), *m_device,
3025                                  context.getUsedApiVersion(), context.getTestContext().getCommandLine());
3026 
3027     m_memoryProperties = vk::getPhysicalDeviceMemoryProperties(inst, physDevice);
3028 
3029     if (params.variant == TestVariant::YCBCR_SAMPLER)
3030     {
3031         m_imageColorFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
3032 
3033         VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = initVulkanStructure();
3034         imageFormatInfo.format                           = m_imageColorFormat;
3035         imageFormatInfo.type                             = VK_IMAGE_TYPE_2D;
3036         imageFormatInfo.tiling                           = VK_IMAGE_TILING_OPTIMAL;
3037         imageFormatInfo.usage                            = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
3038 
3039         VkSamplerYcbcrConversionImageFormatProperties ycbcrFormatProps = initVulkanStructure();
3040         VkImageFormatProperties2 imageFormatProps                      = initVulkanStructure(&ycbcrFormatProps);
3041 
3042         VK_CHECK(m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(
3043             m_context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProps));
3044 
3045         m_combinedImageSamplerDescriptorCount = ycbcrFormatProps.combinedImageSamplerDescriptorCount;
3046 
3047         DE_ASSERT(m_combinedImageSamplerDescriptorCount != 0);
3048     }
3049     else
3050     {
3051         m_imageColorFormat = VK_FORMAT_R32_UINT;
3052     }
3053 
3054     m_allocatorPtr = de::MovePtr<Allocator>(new SimpleAllocator(*m_deviceInterface, *m_device, m_memoryProperties));
3055 }
3056 
getDescriptorSize(const Binding & binding) const3057 VkDeviceSize DescriptorBufferTestInstance::getDescriptorSize(const Binding &binding) const
3058 {
3059     const auto isRobustBufferAccess = (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS);
3060 
3061     // To support mutable descriptor type bindings, we pick the max size from the list below.
3062     // For regular descriptors, there will be only one element in the list.
3063     std::vector<VkDescriptorType> typeList;
3064 
3065     if (binding.isMutableType)
3066     {
3067         DE_ASSERT(m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE);
3068         typeList = getDescriptorMaskTypes(m_params.mutableDescriptorTypes);
3069     }
3070     else
3071     {
3072         typeList.emplace_back(binding.descriptorType);
3073     }
3074 
3075     std::size_t maxSize = 0u;
3076 
3077     for (const auto &type : typeList)
3078     {
3079         std::size_t size = 0u;
3080 
3081         switch (type)
3082         {
3083         case VK_DESCRIPTOR_TYPE_SAMPLER:
3084             size = m_descriptorBufferProperties.samplerDescriptorSize;
3085             break;
3086 
3087         case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3088             size =
3089                 m_descriptorBufferProperties.combinedImageSamplerDescriptorSize * m_combinedImageSamplerDescriptorCount;
3090             break;
3091 
3092         case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3093             size = m_descriptorBufferProperties.sampledImageDescriptorSize;
3094             break;
3095 
3096         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
3097             size = m_descriptorBufferProperties.storageImageDescriptorSize;
3098             break;
3099 
3100         case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
3101             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformTexelBufferDescriptorSize :
3102                                           m_descriptorBufferProperties.uniformTexelBufferDescriptorSize;
3103             break;
3104 
3105         case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
3106             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageTexelBufferDescriptorSize :
3107                                           m_descriptorBufferProperties.storageTexelBufferDescriptorSize;
3108             break;
3109 
3110         case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3111             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustUniformBufferDescriptorSize :
3112                                           m_descriptorBufferProperties.uniformBufferDescriptorSize;
3113             break;
3114 
3115         case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3116             size = isRobustBufferAccess ? m_descriptorBufferProperties.robustStorageBufferDescriptorSize :
3117                                           m_descriptorBufferProperties.storageBufferDescriptorSize;
3118             break;
3119 
3120         case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
3121             size = m_descriptorBufferProperties.inputAttachmentDescriptorSize;
3122             break;
3123 
3124         case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
3125             size = m_descriptorBufferProperties.accelerationStructureDescriptorSize;
3126             break;
3127 
3128         case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
3129             // Inline uniform block has no associated size. This is OK, because it can't be arrayed.
3130             break;
3131 
3132         default:
3133             DE_ASSERT(0);
3134             break;
3135         }
3136 
3137         maxSize = std::max(maxSize, size);
3138     }
3139 
3140     return maxSize;
3141 }
3142 
createDescriptorSetLayouts()3143 void DescriptorBufferTestInstance::createDescriptorSetLayouts()
3144 {
3145     for (auto &dslPtr : m_descriptorSetLayouts)
3146     {
3147         auto &dsl = **dslPtr;
3148 
3149         DE_ASSERT(!dsl.bindings.empty());
3150 
3151         const auto bindingsCopy = getDescriptorSetLayoutBindings(dsl.bindings);
3152 
3153         VkMutableDescriptorTypeCreateInfoEXT mutableDescTypeCreateInfo = initVulkanStructure();
3154         std::vector<VkMutableDescriptorTypeListEXT> mutableDescTypeLists;
3155         std::vector<VkDescriptorType> mutableDescTypeDescriptors;
3156 
3157         VkDescriptorSetLayoutCreateInfo createInfo = initVulkanStructure();
3158         createInfo.bindingCount                    = u32(bindingsCopy.size());
3159         createInfo.pBindings                       = bindingsCopy.data();
3160         createInfo.flags                           = VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
3161 
3162         if (dsl.hasEmbeddedImmutableSamplers)
3163         {
3164             createInfo.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT;
3165         }
3166         else if (dsl.usePushDescriptors)
3167         {
3168             createInfo.flags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
3169         }
3170 
3171         if (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE)
3172         {
3173             // Prepare mutable descriptor type structures
3174 
3175             // NOTE: This test makes a simplification that each mutable descriptor binding has the same
3176             //       set of possible real descriptor types. Due to this, we can use a single descriptor type list.
3177             mutableDescTypeDescriptors = getDescriptorMaskTypes(m_params.mutableDescriptorTypes);
3178             mutableDescTypeLists.resize(createInfo.bindingCount);
3179 
3180             createInfo.pNext                                         = &mutableDescTypeCreateInfo;
3181             mutableDescTypeCreateInfo.mutableDescriptorTypeListCount = u32(mutableDescTypeLists.size());
3182             mutableDescTypeCreateInfo.pMutableDescriptorTypeLists    = mutableDescTypeLists.data();
3183 
3184             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
3185             {
3186                 const auto &binding = dsl.bindings[bindingIndex];
3187 
3188                 if (binding.isMutableType)
3189                 {
3190                     DE_ASSERT(binding.immutableSamplers[0] == DE_NULL);
3191                     mutableDescTypeLists[bindingIndex].descriptorTypeCount = u32(mutableDescTypeDescriptors.size());
3192                     mutableDescTypeLists[bindingIndex].pDescriptorTypes    = mutableDescTypeDescriptors.data();
3193                 }
3194                 else
3195                 {
3196                     mutableDescTypeLists[bindingIndex].descriptorTypeCount = 0;
3197                     mutableDescTypeLists[bindingIndex].pDescriptorTypes    = nullptr;
3198                 }
3199             }
3200 
3201             // Check support
3202 
3203             VkDescriptorSetLayoutSupport support = initVulkanStructure();
3204 
3205             m_deviceInterface->getDescriptorSetLayoutSupport(*m_device, &createInfo, &support);
3206 
3207             if (support.supported == VK_FALSE)
3208             {
3209                 TCU_THROW(NotSupportedError, "Descriptor set layout is not supported");
3210             }
3211         }
3212 
3213         dsl.layout = createDescriptorSetLayout(*m_deviceInterface, *m_device, &createInfo);
3214 
3215         m_deviceInterface->getDescriptorSetLayoutSizeEXT(*m_device, *dsl.layout, &dsl.sizeOfLayout);
3216 
3217         for (auto &binding : dsl.bindings)
3218         {
3219             m_deviceInterface->getDescriptorSetLayoutBindingOffsetEXT(*m_device, *dsl.layout, binding.binding,
3220                                                                       &binding.offset);
3221         }
3222     }
3223 }
3224 
3225 // The test may create a variable number of descriptor buffers, based on the parameters.
3226 //
createDescriptorBuffers()3227 void DescriptorBufferTestInstance::createDescriptorBuffers()
3228 {
3229     DE_ASSERT(m_descriptorBuffers.empty());
3230 
3231     const uint8_t bufferInitialMemory             = 0xcc;  // descriptor buffer memory is initially set to this
3232     bool allocateStagingBuffer                    = false; // determined after descriptors are created
3233     VkDeviceSize stagingBufferDescriptorSetOffset = 0;
3234     const uint32_t setsPerBuffer =
3235         m_params.subcase == SubCase::SINGLE_BUFFER ? m_params.bufferBindingCount + 1 : m_params.setsPerBuffer;
3236 
3237     // Data tracked per buffer creation
3238     struct
3239     {
3240         uint32_t firstSet;
3241         uint32_t numSets;
3242         VkBufferUsageFlags usage;
3243         VkDeviceSize setOffset;
3244     } currentBuffer;
3245 
3246     currentBuffer = {};
3247 
3248     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3249     {
3250         auto &dsl = **m_descriptorSetLayouts[setIndex];
3251 
3252         if (dsl.hasEmbeddedImmutableSamplers ||
3253             (dsl.usePushDescriptors && m_descriptorBufferProperties.bufferlessPushDescriptors &&
3254              m_params.subcase != SubCase::SINGLE_BUFFER))
3255         {
3256             // Embedded immutable samplers aren't backed by a descriptor buffer.
3257             // Same goes for the set used with push descriptors.
3258             // Push descriptors might require buffer. If so, don't skip creation of buffer.
3259 
3260             // We musn't have started adding sets to the next buffer yet.
3261             DE_ASSERT(currentBuffer.numSets == 0);
3262             ++currentBuffer.firstSet;
3263 
3264             continue;
3265         }
3266 
3267         // Required for binding
3268         currentBuffer.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
3269 
3270         for (const auto &binding : dsl.bindings)
3271         {
3272             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
3273             {
3274                 currentBuffer.usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT;
3275             }
3276             else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
3277             {
3278                 currentBuffer.usage |= VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT |
3279                                        VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;
3280             }
3281             else
3282             {
3283                 currentBuffer.usage |= VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;
3284             }
3285         }
3286 
3287         if (!m_descriptorBufferProperties.bufferlessPushDescriptors && dsl.usePushDescriptors)
3288         {
3289             currentBuffer.usage |= VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT;
3290         }
3291 
3292         // Allow descriptor set layout to be size of zero bytes
3293         if (dsl.sizeOfLayout != 0)
3294         {
3295             // Assign this descriptor set to a new buffer
3296             dsl.bufferIndex  = u32(m_descriptorBuffers.size());
3297             dsl.bufferOffset = currentBuffer.setOffset;
3298         }
3299 
3300         currentBuffer.numSets += 1;
3301         currentBuffer.setOffset +=
3302             deAlignSize(static_cast<std::size_t>(dsl.sizeOfLayout),
3303                         static_cast<std::size_t>(m_descriptorBufferProperties.descriptorBufferOffsetAlignment));
3304 
3305         VkMemoryAllocateFlagsInfo allocFlagsInfo = initVulkanStructure();
3306         allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
3307 
3308         // We've reached the limit of sets for this descriptor buffer.
3309         if (currentBuffer.numSets == setsPerBuffer)
3310         {
3311             vk::VkBufferCreateInfo bufferCreateInfo =
3312                 makeBufferCreateInfo(currentBuffer.setOffset, currentBuffer.usage);
3313 
3314             if (bufferCreateInfo.size != 0)
3315             {
3316                 m_descriptorBuffers.emplace_back(new BufferAlloc());
3317                 auto &bufferAlloc = *m_descriptorBuffers.back();
3318 
3319                 bufferAlloc.size  = bufferCreateInfo.size;
3320                 bufferAlloc.usage = bufferCreateInfo.usage;
3321 
3322                 vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = initVulkanStructure();
3323                 ;
3324                 if (m_params.useMaintenance5)
3325                 {
3326                     bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)currentBuffer.usage;
3327                     bufferCreateInfo.pNext  = &bufferUsageFlags2;
3328                     bufferCreateInfo.usage  = 0;
3329                 }
3330 
3331                 bufferAlloc.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3332 
3333                 auto bufferMemReqs   = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferAlloc.buffer);
3334                 bool useStagedUpload = false; // write directly to device-local memory, if possible
3335 
3336                 if (DEBUG_FORCE_STAGED_UPLOAD)
3337                 {
3338                     useStagedUpload = true;
3339                 }
3340                 else if (DEBUG_MIX_DIRECT_AND_STAGED_UPLOAD)
3341                 {
3342                     // To avoid adding yet another test case permutation (which may be redundant on some implementations),
3343                     // we are going to always test a mix of direct and staged uploads.
3344                     useStagedUpload = ((dsl.bufferIndex % 2) == 1);
3345                 }
3346 
3347                 if (!useStagedUpload)
3348                 {
3349                     auto memReqs = MemoryRequirement::Local | MemoryRequirement::HostVisible;
3350                     auto compatMask =
3351                         bufferMemReqs.memoryTypeBits & getCompatibleMemoryTypes(m_memoryProperties, memReqs);
3352 
3353                     if (compatMask != 0)
3354                     {
3355                         bufferAlloc.alloc = allocate(bufferMemReqs, memReqs, &allocFlagsInfo);
3356                     }
3357                     else
3358                     {
3359                         // No suitable memory type, fall back to a staged upload
3360                         useStagedUpload = true;
3361                     }
3362                 }
3363 
3364                 if (useStagedUpload)
3365                 {
3366                     DE_ASSERT(!bufferAlloc.alloc);
3367 
3368                     if ((bufferAlloc.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) == 0)
3369                     {
3370                         bufferAlloc.buffer = Move<VkBuffer>();
3371                         bufferAlloc.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
3372 
3373                         bufferCreateInfo.usage = bufferAlloc.usage;
3374 
3375                         bufferAlloc.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3376 
3377                         bufferMemReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferAlloc.buffer);
3378                     }
3379 
3380                     bufferAlloc.alloc     = allocate(bufferMemReqs, MemoryRequirement::Local, &allocFlagsInfo);
3381                     allocateStagingBuffer = true;
3382 
3383                     // Update staging buffer offsets for all sets in this buffer
3384                     for (uint32_t i = currentBuffer.firstSet; i < currentBuffer.firstSet + currentBuffer.numSets; ++i)
3385                     {
3386                         (**m_descriptorSetLayouts[i]).stagingBufferOffset = stagingBufferDescriptorSetOffset;
3387                         stagingBufferDescriptorSetOffset += (**m_descriptorSetLayouts[i]).sizeOfLayout;
3388                     }
3389                 }
3390 
3391                 VK_CHECK(m_deviceInterface->bindBufferMemory(
3392                     *m_device, *bufferAlloc.buffer, bufferAlloc.alloc->getMemory(), bufferAlloc.alloc->getOffset()));
3393 
3394                 bufferAlloc.loadDeviceAddress(*m_deviceInterface, *m_device);
3395 
3396                 if (!useStagedUpload)
3397                 {
3398                     // Clear the descriptor buffer memory to ensure there can be no random data there.
3399                     deMemset(bufferAlloc.alloc->getHostPtr(), bufferInitialMemory,
3400                              static_cast<std::size_t>(bufferAlloc.size));
3401                 }
3402             }
3403 
3404             // Start with a new buffer
3405             currentBuffer          = {};
3406             currentBuffer.firstSet = setIndex + 1;
3407         }
3408     }
3409 
3410     if (allocateStagingBuffer)
3411     {
3412         DE_ASSERT(!m_descriptorStagingBuffer.alloc);
3413 
3414         auto bufferCreateInfo =
3415             makeBufferCreateInfo(stagingBufferDescriptorSetOffset, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
3416 
3417         m_descriptorStagingBuffer.buffer = vk::createBuffer(*m_deviceInterface, *m_device, &bufferCreateInfo);
3418         m_descriptorStagingBuffer.size   = bufferCreateInfo.size;
3419 
3420         auto bufferMemReqs =
3421             getBufferMemoryRequirements(*m_deviceInterface, *m_device, *m_descriptorStagingBuffer.buffer);
3422 
3423         m_descriptorStagingBuffer.alloc = allocate(bufferMemReqs, MemoryRequirement::HostVisible);
3424 
3425         VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *m_descriptorStagingBuffer.buffer,
3426                                                      m_descriptorStagingBuffer.alloc->getMemory(),
3427                                                      m_descriptorStagingBuffer.alloc->getOffset()));
3428 
3429         // Clear the descriptor buffer memory to ensure there can be no random data there.
3430         deMemset(m_descriptorStagingBuffer.alloc->getHostPtr(), bufferInitialMemory,
3431                  static_cast<std::size_t>(m_descriptorStagingBuffer.size));
3432     }
3433 }
3434 
bindDescriptorBuffers(VkCommandBuffer cmdBuf,VkPipelineBindPoint bindPoint) const3435 void DescriptorBufferTestInstance::bindDescriptorBuffers(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint) const
3436 {
3437     std::vector<uint32_t> bufferIndices;
3438     std::vector<VkDeviceSize> bufferOffsets;
3439     std::vector<VkDescriptorBufferBindingInfoEXT> bufferBindingInfos;
3440     VkDescriptorBufferBindingPushDescriptorBufferHandleEXT bufferBindingPushDescriptorBufferHandleEXT =
3441         initVulkanStructure();
3442 
3443     uint32_t firstSet = 0;
3444 
3445     if (m_params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
3446     {
3447         // These sampler sets are ordered first, so we can bind them now and increment the firstSet index.
3448         for (uint32_t setIndex = firstSet; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3449         {
3450             const auto &dsl = **m_descriptorSetLayouts[setIndex];
3451 
3452             if (dsl.hasEmbeddedImmutableSamplers)
3453             {
3454                 if (m_params.commands2)
3455                 {
3456                     vk::VkBindDescriptorBufferEmbeddedSamplersInfoEXT bindDescriptorBufferEmbeddedSamplersInfo = {
3457                         VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_BUFFER_EMBEDDED_SAMPLERS_INFO_EXT, // VkStructureType sType;
3458                         DE_NULL,                                                             // const void* pNext;
3459                         (VkShaderStageFlags)m_params.stage, // VkShaderStageFlags stageFlags;
3460                         *m_pipelineLayout,                  // VkPipelineLayout layout;
3461                         setIndex                            // uint32_t set;
3462                     };
3463                     m_deviceInterface->cmdBindDescriptorBufferEmbeddedSamplers2EXT(
3464                         cmdBuf, &bindDescriptorBufferEmbeddedSamplersInfo);
3465                 }
3466                 else
3467                 {
3468                     m_deviceInterface->cmdBindDescriptorBufferEmbeddedSamplersEXT(cmdBuf, bindPoint, *m_pipelineLayout,
3469                                                                                   setIndex);
3470                 }
3471 
3472                 // No gaps between sets.
3473                 DE_ASSERT(firstSet == setIndex);
3474 
3475                 firstSet = setIndex + 1;
3476             }
3477         }
3478     }
3479 
3480     for (const auto &buffer : m_descriptorBuffers)
3481     {
3482         VkDescriptorBufferBindingInfoEXT info = initVulkanStructure();
3483 
3484         info.address = buffer->deviceAddress;
3485         info.usage   = buffer->usage;
3486 
3487         if (!m_descriptorBufferProperties.bufferlessPushDescriptors &&
3488             (buffer->usage & VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT) != 0)
3489         {
3490             info.pNext = &bufferBindingPushDescriptorBufferHandleEXT;
3491 
3492             // Make sure there is only one such buffer
3493             DE_ASSERT(bufferBindingPushDescriptorBufferHandleEXT.buffer == DE_NULL);
3494 
3495             bufferBindingPushDescriptorBufferHandleEXT.buffer = *buffer->buffer;
3496 
3497             DE_ASSERT(bufferBindingPushDescriptorBufferHandleEXT.buffer != DE_NULL);
3498         }
3499 
3500         bufferBindingInfos.emplace_back(info);
3501     }
3502 
3503     if (bufferBindingInfos.size() != 0u)
3504     {
3505         m_deviceInterface->cmdBindDescriptorBuffersEXT(cmdBuf, u32(bufferBindingInfos.size()),
3506                                                        bufferBindingInfos.data());
3507     }
3508 
3509     // Next, set the offsets for the bound buffers.
3510 
3511     for (uint32_t setIndex = firstSet; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3512     {
3513         const auto &dsl       = **m_descriptorSetLayouts[setIndex];
3514         const bool isBoundSet = (dsl.bufferIndex != INDEX_INVALID);
3515         const bool isLastSet  = ((setIndex + 1) == u32(m_descriptorSetLayouts.size()));
3516 
3517         if (isBoundSet)
3518         {
3519             bufferIndices.emplace_back(dsl.bufferIndex);
3520             bufferOffsets.emplace_back(dsl.bufferOffset);
3521         }
3522 
3523         if ((!isBoundSet || isLastSet) && !bufferIndices.empty())
3524         {
3525             if (m_params.commands2)
3526             {
3527                 vk::VkSetDescriptorBufferOffsetsInfoEXT setDescriptorBufferOffsetInfo = {
3528                     VK_STRUCTURE_TYPE_SET_DESCRIPTOR_BUFFER_OFFSETS_INFO_EXT, // VkStructureType sType;
3529                     DE_NULL,                                                  // const void* pNext;
3530                     (VkShaderStageFlags)m_params.stage,                       // VkShaderStageFlags stageFlags;
3531                     *m_pipelineLayout,                                        // VkPipelineLayout layout;
3532                     firstSet,                                                 // uint32_t firstSet;
3533                     u32(bufferIndices.size()),                                // uint32_t setCount;
3534                     bufferIndices.data(),                                     // const uint32_t* pBufferIndices;
3535                     bufferOffsets.data()                                      // const VkDeviceSize* pOffsets;
3536                 };
3537                 m_deviceInterface->cmdSetDescriptorBufferOffsets2EXT(cmdBuf, &setDescriptorBufferOffsetInfo);
3538             }
3539             else
3540             {
3541                 m_deviceInterface->cmdSetDescriptorBufferOffsetsEXT(cmdBuf, bindPoint, *m_pipelineLayout, firstSet,
3542                                                                     u32(bufferIndices.size()), bufferIndices.data(),
3543                                                                     bufferOffsets.data());
3544             }
3545 
3546             bufferIndices.clear();
3547             bufferOffsets.clear();
3548 
3549             firstSet = setIndex + 1;
3550         }
3551         else if (!isBoundSet)
3552         {
3553             // Push descriptor sets will have no buffer backing. Skip this set.
3554             ++firstSet;
3555         }
3556     }
3557 }
3558 
makeShaderStageCreateInfo(VkShaderStageFlagBits stage,VkShaderModule shaderModule)3559 VkPipelineShaderStageCreateInfo makeShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule shaderModule)
3560 {
3561     VkPipelineShaderStageCreateInfo createInfo = initVulkanStructure();
3562     createInfo.stage                           = stage;
3563     createInfo.module                          = shaderModule;
3564     createInfo.pName                           = "main";
3565     createInfo.pSpecializationInfo             = nullptr;
3566     return createInfo;
3567 }
3568 
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)3569 de::MovePtr<BufferWithMemory> DescriptorBufferTestInstance::createShaderBindingTable(
3570     const InstanceInterface &vki, const DeviceInterface &vkd, const VkDevice device,
3571     const VkPhysicalDevice physicalDevice, const VkPipeline pipeline, Allocator &allocator,
3572     de::MovePtr<RayTracingPipeline> &rayTracingPipeline, const uint32_t group)
3573 {
3574     de::MovePtr<BufferWithMemory> shaderBindingTable;
3575 
3576     if (group < m_shaderGroupCount)
3577     {
3578         const uint32_t shaderGroupHandleSize    = getShaderGroupHandleSize(vki, physicalDevice);
3579         const uint32_t shaderGroupBaseAlignment = getShaderGroupBaseAlignment(vki, physicalDevice);
3580 
3581         shaderBindingTable = rayTracingPipeline->createShaderBindingTable(
3582             vkd, device, pipeline, allocator, shaderGroupHandleSize, shaderGroupBaseAlignment, group, 1u);
3583     }
3584 
3585     return shaderBindingTable;
3586 }
3587 
createRayTracingPipeline()3588 void DescriptorBufferTestInstance::createRayTracingPipeline()
3589 {
3590     const InstanceInterface &vki          = m_context.getInstanceInterface();
3591     const DeviceInterface &vkd            = *m_deviceInterface;
3592     const VkDevice device                 = *m_device;
3593     const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
3594     vk::BinaryCollection &collection      = m_context.getBinaryCollection();
3595     Allocator &allocator                  = *m_allocatorPtr;
3596     const uint32_t shaderGroupHandleSize  = getShaderGroupHandleSize(vki, physicalDevice);
3597     const VkShaderStageFlags hitStages =
3598         VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
3599 
3600     m_shaderGroupCount = 0;
3601 
3602     if (collection.contains(getShaderName(VK_SHADER_STAGE_RAYGEN_BIT_KHR)))
3603         m_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;
3604     if (collection.contains(getShaderName(VK_SHADER_STAGE_ANY_HIT_BIT_KHR)))
3605         m_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
3606     if (collection.contains(getShaderName(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR)))
3607         m_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
3608     if (collection.contains(getShaderName(VK_SHADER_STAGE_MISS_BIT_KHR)))
3609         m_shaders |= VK_SHADER_STAGE_MISS_BIT_KHR;
3610     if (collection.contains(getShaderName(VK_SHADER_STAGE_INTERSECTION_BIT_KHR)))
3611         m_shaders |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
3612     if (collection.contains(getShaderName(VK_SHADER_STAGE_CALLABLE_BIT_KHR)))
3613         m_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;
3614 
3615     if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
3616         m_raygenShaderGroup = m_shaderGroupCount++;
3617 
3618     if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
3619         m_missShaderGroup = m_shaderGroupCount++;
3620 
3621     if (0 != (m_shaders & hitStages))
3622         m_hitShaderGroup = m_shaderGroupCount++;
3623 
3624     if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR))
3625         m_callableShaderGroup = m_shaderGroupCount++;
3626 
3627     m_rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
3628 
3629     m_rayTracingPipeline->setCreateFlags(VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT);
3630 
3631     if (0 != (m_shaders & VK_SHADER_STAGE_RAYGEN_BIT_KHR))
3632         addRayTracingShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, m_raygenShaderGroup);
3633     if (0 != (m_shaders & VK_SHADER_STAGE_ANY_HIT_BIT_KHR))
3634         addRayTracingShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, m_hitShaderGroup);
3635     if (0 != (m_shaders & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR))
3636         addRayTracingShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, m_hitShaderGroup);
3637     if (0 != (m_shaders & VK_SHADER_STAGE_MISS_BIT_KHR))
3638         addRayTracingShader(VK_SHADER_STAGE_MISS_BIT_KHR, m_missShaderGroup);
3639     if (0 != (m_shaders & VK_SHADER_STAGE_INTERSECTION_BIT_KHR))
3640         addRayTracingShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, m_hitShaderGroup);
3641     if (0 != (m_shaders & VK_SHADER_STAGE_CALLABLE_BIT_KHR))
3642         addRayTracingShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, m_callableShaderGroup);
3643 
3644     m_pipelineLayout = makePipelineLayout(vkd, device, getDescriptorSetLayouts(m_descriptorSetLayouts));
3645     m_pipeline       = m_rayTracingPipeline->createPipeline(vkd, device, *m_pipelineLayout);
3646 
3647     m_raygenShaderBindingTable   = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3648                                                             m_rayTracingPipeline, m_raygenShaderGroup);
3649     m_missShaderBindingTable     = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3650                                                             m_rayTracingPipeline, m_missShaderGroup);
3651     m_hitShaderBindingTable      = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3652                                                             m_rayTracingPipeline, m_hitShaderGroup);
3653     m_callableShaderBindingTable = createShaderBindingTable(vki, vkd, device, physicalDevice, *m_pipeline, allocator,
3654                                                             m_rayTracingPipeline, m_callableShaderGroup);
3655 
3656     m_raygenShaderBindingTableRegion =
3657         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_raygenShaderBindingTable), shaderGroupHandleSize);
3658     m_missShaderBindingTableRegion =
3659         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_missShaderBindingTable), shaderGroupHandleSize);
3660     m_hitShaderBindingTableRegion =
3661         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_hitShaderBindingTable), shaderGroupHandleSize);
3662     m_callableShaderBindingTableRegion =
3663         makeStridedDeviceAddressRegion(vkd, device, getVkBuffer(m_callableShaderBindingTable), shaderGroupHandleSize);
3664 }
3665 
addRayTracingShader(const VkShaderStageFlagBits stage,const uint32_t group)3666 void DescriptorBufferTestInstance::addRayTracingShader(const VkShaderStageFlagBits stage, const uint32_t group)
3667 {
3668     DE_ASSERT(m_rayTracingPipeline != DE_NULL);
3669 
3670     m_rayTracingPipeline->addShader(stage, createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(stage), 0),
3671                                     group);
3672 }
3673 
3674 // The graphics pipeline is very simple for this test.
3675 // The number of shader stages is configurable. There's no vertex input, a single triangle covers the entire viewport.
3676 // The color target uses R32_UINT format and is used to save the verifcation result.
3677 //
createGraphicsPipeline()3678 void DescriptorBufferTestInstance::createGraphicsPipeline()
3679 {
3680     std::vector<VkImageView> framebufferAttachments;
3681 
3682     {
3683         m_colorImage.info                       = initVulkanStructure();
3684         m_colorImage.info.flags                 = 0;
3685         m_colorImage.info.imageType             = VK_IMAGE_TYPE_2D;
3686         m_colorImage.info.format                = VK_FORMAT_R32_UINT;
3687         m_colorImage.info.extent.width          = m_renderArea.extent.width;
3688         m_colorImage.info.extent.height         = m_renderArea.extent.height;
3689         m_colorImage.info.extent.depth          = 1;
3690         m_colorImage.info.mipLevels             = 1;
3691         m_colorImage.info.arrayLayers           = 1;
3692         m_colorImage.info.samples               = VK_SAMPLE_COUNT_1_BIT;
3693         m_colorImage.info.tiling                = VK_IMAGE_TILING_OPTIMAL;
3694         m_colorImage.info.usage                 = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
3695         m_colorImage.info.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3696         m_colorImage.info.queueFamilyIndexCount = 0;
3697         m_colorImage.info.pQueueFamilyIndices   = nullptr;
3698         m_colorImage.info.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
3699 
3700         m_colorImage.image = createImage(*m_deviceInterface, *m_device, &m_colorImage.info);
3701 
3702         auto memReqs           = getImageMemoryRequirements(*m_deviceInterface, *m_device, *m_colorImage.image);
3703         m_colorImage.sizeBytes = memReqs.size;
3704         m_colorImage.alloc     = allocate(memReqs, MemoryRequirement::Local);
3705 
3706         VK_CHECK(m_deviceInterface->bindImageMemory(*m_device, *m_colorImage.image, m_colorImage.alloc->getMemory(),
3707                                                     m_colorImage.alloc->getOffset()));
3708     }
3709     {
3710         auto createInfo = makeBufferCreateInfo(m_colorImage.sizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
3711 
3712         m_colorBuffer.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3713 
3714         auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *m_colorBuffer.buffer);
3715 
3716         m_colorBuffer.alloc = allocate(memReqs, MemoryRequirement::HostVisible);
3717         VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *m_colorBuffer.buffer, m_colorBuffer.alloc->getMemory(),
3718                                                      m_colorBuffer.alloc->getOffset()));
3719     }
3720     {
3721         VkImageViewCreateInfo createInfo = initVulkanStructure();
3722         createInfo.image                 = *m_colorImage.image;
3723         createInfo.viewType              = VK_IMAGE_VIEW_TYPE_2D;
3724         createInfo.format                = m_colorImage.info.format;
3725         createInfo.components            = ComponentMappingIdentity;
3726         createInfo.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
3727 
3728         m_colorImage.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
3729     }
3730 
3731     framebufferAttachments.push_back(*m_colorImage.imageView);
3732 
3733     {
3734         std::vector<VkAttachmentDescription> attachments;
3735         std::vector<VkAttachmentReference> colorRefs;
3736         std::vector<VkAttachmentReference> inputRefs;
3737 
3738         {
3739             VkAttachmentDescription colorAttachment{};
3740             colorAttachment.format         = VK_FORMAT_R32_UINT;
3741             colorAttachment.samples        = VK_SAMPLE_COUNT_1_BIT;
3742             colorAttachment.loadOp         = VK_ATTACHMENT_LOAD_OP_CLEAR;
3743             colorAttachment.storeOp        = VK_ATTACHMENT_STORE_OP_STORE;
3744             colorAttachment.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3745             colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3746             colorAttachment.initialLayout  = VK_IMAGE_LAYOUT_UNDEFINED;
3747             colorAttachment.finalLayout    = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3748 
3749             colorRefs.emplace_back(
3750                 makeAttachmentReference(u32(attachments.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
3751             attachments.emplace_back(colorAttachment);
3752         }
3753 
3754         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
3755         {
3756             const auto &dsl = **m_descriptorSetLayouts[setIndex];
3757 
3758             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
3759             {
3760                 const auto &binding = dsl.bindings[bindingIndex];
3761 
3762                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
3763                 {
3764                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
3765                     {
3766                         VkAttachmentDescription inputAttachment{};
3767                         inputAttachment.format         = m_imageColorFormat;
3768                         inputAttachment.samples        = VK_SAMPLE_COUNT_1_BIT;
3769                         inputAttachment.loadOp         = VK_ATTACHMENT_LOAD_OP_LOAD;
3770                         inputAttachment.storeOp        = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3771                         inputAttachment.stencilLoadOp  = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3772                         inputAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
3773                         inputAttachment.initialLayout  = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3774                         inputAttachment.finalLayout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
3775 
3776                         inputRefs.emplace_back(
3777                             makeAttachmentReference(u32(attachments.size()), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
3778                         attachments.emplace_back(inputAttachment);
3779 
3780                         const auto inputAttachmentResourceIndex = binding.perBindingResourceIndex[arrayIndex];
3781                         framebufferAttachments.push_back(
3782                             *(**m_resources[inputAttachmentResourceIndex]).image.imageView);
3783                     }
3784                 }
3785             }
3786         }
3787 
3788         VkSubpassDescription subpass{};
3789         subpass.pipelineBindPoint       = VK_PIPELINE_BIND_POINT_GRAPHICS;
3790         subpass.inputAttachmentCount    = u32(inputRefs.size());
3791         subpass.pInputAttachments       = inputRefs.data();
3792         subpass.colorAttachmentCount    = u32(colorRefs.size());
3793         subpass.pColorAttachments       = colorRefs.data();
3794         subpass.pResolveAttachments     = nullptr;
3795         subpass.pDepthStencilAttachment = nullptr;
3796         subpass.preserveAttachmentCount = 0;
3797         subpass.pPreserveAttachments    = nullptr;
3798 
3799         VkRenderPassCreateInfo createInfo = initVulkanStructure();
3800         // No explicit dependencies
3801         createInfo.attachmentCount = u32(attachments.size());
3802         createInfo.pAttachments    = attachments.data();
3803         createInfo.subpassCount    = 1;
3804         createInfo.pSubpasses      = &subpass;
3805 
3806         m_renderPass = createRenderPass(*m_deviceInterface, *m_device, &createInfo);
3807     }
3808     {
3809         VkFramebufferCreateInfo createInfo = initVulkanStructure();
3810         createInfo.renderPass              = *m_renderPass;
3811         createInfo.attachmentCount         = u32(framebufferAttachments.size());
3812         createInfo.pAttachments            = framebufferAttachments.data();
3813         createInfo.width                   = m_renderArea.extent.width;
3814         createInfo.height                  = m_renderArea.extent.height;
3815         createInfo.layers                  = 1;
3816 
3817         m_framebuffer = createFramebuffer(*m_deviceInterface, *m_device, &createInfo);
3818     }
3819 
3820     std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
3821 
3822     Move<VkShaderModule> vertModule;
3823     Move<VkShaderModule> tessControlModule;
3824     Move<VkShaderModule> tessEvalModule;
3825     Move<VkShaderModule> geomModule;
3826     Move<VkShaderModule> fragModule;
3827 
3828     vertModule = createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_VERTEX_BIT), 0u);
3829     fragModule = createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_FRAGMENT_BIT), 0u);
3830 
3831     shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, *vertModule));
3832     shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, *fragModule));
3833 
3834     if (m_params.isTessellation())
3835     {
3836         tessControlModule = createShaderModule(*m_deviceInterface, *m_device,
3837                                                getShaderBinary(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), 0u);
3838         tessEvalModule    = createShaderModule(*m_deviceInterface, *m_device,
3839                                                getShaderBinary(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), 0u);
3840 
3841         shaderStages.emplace_back(
3842             makeShaderStageCreateInfo(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, *tessControlModule));
3843         shaderStages.emplace_back(
3844             makeShaderStageCreateInfo(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, *tessEvalModule));
3845     }
3846     else if (m_params.isGeometry())
3847     {
3848         geomModule =
3849             createShaderModule(*m_deviceInterface, *m_device, getShaderBinary(VK_SHADER_STAGE_GEOMETRY_BIT), 0u);
3850 
3851         shaderStages.emplace_back(makeShaderStageCreateInfo(VK_SHADER_STAGE_GEOMETRY_BIT, *geomModule));
3852     }
3853 
3854     VkPipelineVertexInputStateCreateInfo vertexInputState = initVulkanStructure();
3855     // No vertex input
3856 
3857     VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = initVulkanStructure();
3858     inputAssemblyState.topology =
3859         !!tessControlModule ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
3860 
3861     VkPipelineTessellationStateCreateInfo tesselationState = initVulkanStructure();
3862     tesselationState.patchControlPoints                    = 3;
3863 
3864     VkViewport viewport = makeViewport(m_renderArea.extent);
3865 
3866     VkPipelineViewportStateCreateInfo viewportState = initVulkanStructure();
3867     viewportState.viewportCount                     = 1;
3868     viewportState.pViewports                        = &viewport;
3869     viewportState.scissorCount                      = 1;
3870     viewportState.pScissors                         = &m_renderArea;
3871 
3872     VkPipelineRasterizationStateCreateInfo rasterizationState = initVulkanStructure();
3873     rasterizationState.depthClampEnable                       = VK_FALSE;
3874     rasterizationState.rasterizerDiscardEnable                = VK_FALSE;
3875     rasterizationState.polygonMode                            = VK_POLYGON_MODE_FILL;
3876     rasterizationState.cullMode                               = VK_CULL_MODE_NONE;
3877     rasterizationState.frontFace                              = VK_FRONT_FACE_COUNTER_CLOCKWISE;
3878     rasterizationState.depthBiasEnable                        = VK_FALSE;
3879     rasterizationState.depthBiasConstantFactor                = 0.0f;
3880     rasterizationState.depthBiasClamp                         = 0.0f;
3881     rasterizationState.depthBiasSlopeFactor                   = 0.0f;
3882     rasterizationState.lineWidth                              = 1.0f;
3883 
3884     VkPipelineMultisampleStateCreateInfo multisampleState = initVulkanStructure();
3885     // Everything else disabled/default
3886     multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
3887 
3888     VkPipelineDepthStencilStateCreateInfo depthStencilState = initVulkanStructure();
3889     // Everything else disabled/default
3890     depthStencilState.minDepthBounds = 0.0f;
3891     depthStencilState.maxDepthBounds = 1.0f;
3892 
3893     VkPipelineColorBlendAttachmentState colorAttachment{};
3894     // Everything else disabled/default
3895     colorAttachment.colorWriteMask =
3896         VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
3897 
3898     VkPipelineColorBlendStateCreateInfo colorBlendState = initVulkanStructure();
3899     // Everything else disabled/default
3900     colorBlendState.attachmentCount = 1;
3901     colorBlendState.pAttachments    = &colorAttachment;
3902 
3903     {
3904         VkGraphicsPipelineCreateInfo createInfo = initVulkanStructure();
3905         createInfo.stageCount                   = u32(shaderStages.size());
3906         createInfo.pStages                      = shaderStages.data();
3907         createInfo.pVertexInputState            = &vertexInputState;
3908         createInfo.pInputAssemblyState          = &inputAssemblyState;
3909         createInfo.pTessellationState           = m_params.isTessellation() ? &tesselationState : nullptr;
3910         createInfo.pViewportState               = &viewportState;
3911         createInfo.pRasterizationState          = &rasterizationState;
3912         createInfo.pMultisampleState            = &multisampleState;
3913         createInfo.pDepthStencilState           = &depthStencilState;
3914         createInfo.pColorBlendState             = &colorBlendState;
3915         createInfo.pDynamicState                = nullptr;
3916         createInfo.layout                       = *m_pipelineLayout;
3917         createInfo.renderPass                   = *m_renderPass;
3918         createInfo.subpass                      = 0;
3919         createInfo.basePipelineHandle           = DE_NULL;
3920         createInfo.basePipelineIndex            = -1;
3921         createInfo.flags                        = VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT;
3922 
3923         m_pipeline = vk::createGraphicsPipeline(*m_deviceInterface, *m_device,
3924                                                 DE_NULL, // pipeline cache
3925                                                 &createInfo);
3926     }
3927 }
3928 
createBufferForBinding(ResourceHolder & resources,VkDescriptorType descriptorType,VkBufferCreateInfo createInfo,bool isResultBuffer) const3929 void DescriptorBufferTestInstance::createBufferForBinding(ResourceHolder &resources, VkDescriptorType descriptorType,
3930                                                           VkBufferCreateInfo createInfo, bool isResultBuffer) const
3931 {
3932     auto &bufferResource    = resources.buffer;
3933     auto &captureReplayData = resources.captureReplay.bufferData;
3934 
3935     createInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
3936 
3937     if (!isResultBuffer && isCaptureDescriptor(descriptorType))
3938     {
3939         createInfo.flags |= VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
3940 
3941         DE_ASSERT(!bufferResource.buffer);
3942         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3943 
3944         VkBufferCaptureDescriptorDataInfoEXT info = initVulkanStructure();
3945         info.buffer                               = *bufferResource.buffer;
3946 
3947         DE_ASSERT(captureReplayData.empty());
3948         captureReplayData.resize(m_descriptorBufferProperties.bufferCaptureReplayDescriptorDataSize);
3949 
3950         VK_CHECK(
3951             m_deviceInterface->getBufferOpaqueCaptureDescriptorDataEXT(*m_device, &info, captureReplayData.data()));
3952     }
3953     else if (!isResultBuffer && isReplayDescriptor(descriptorType))
3954     {
3955         // Free the previous buffer and its memory
3956         reset(bufferResource.buffer);
3957         reset(bufferResource.alloc);
3958 
3959         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
3960         info.opaqueCaptureDescriptorData                = captureReplayData.data();
3961 
3962         createInfo.flags |= VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
3963         createInfo.pNext = &info;
3964 
3965         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3966     }
3967     else
3968     {
3969         DE_ASSERT(!bufferResource.buffer);
3970         bufferResource.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
3971     }
3972 
3973     auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *bufferResource.buffer);
3974 
3975     VkMemoryOpaqueCaptureAddressAllocateInfo opaqueCaptureAddressAllocateInfo = initVulkanStructure();
3976     VkMemoryAllocateFlagsInfo allocFlagsInfo                                  = initVulkanStructure();
3977     allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
3978 
3979     if (!isResultBuffer && m_params.isCaptureReplayDescriptor(descriptorType))
3980     {
3981         allocFlagsInfo.flags |= VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT;
3982         allocFlagsInfo.pNext = &opaqueCaptureAddressAllocateInfo;
3983 
3984         if (isCaptureDescriptor(descriptorType))
3985         {
3986             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = 0ull;
3987         }
3988         else if (isReplayDescriptor(descriptorType))
3989         {
3990             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = bufferResource.opaqueCaptureAddress;
3991         }
3992     }
3993 
3994     DE_ASSERT(!bufferResource.alloc);
3995     bufferResource.alloc = allocate(memReqs, MemoryRequirement::HostVisible, &allocFlagsInfo);
3996 
3997     if (isCaptureDescriptor(descriptorType))
3998     {
3999         VkDeviceMemoryOpaqueCaptureAddressInfo memoryOpaqueCaptureAddressInfo = initVulkanStructure();
4000 
4001         memoryOpaqueCaptureAddressInfo.memory = bufferResource.alloc->getMemory();
4002 
4003         bufferResource.opaqueCaptureAddress =
4004             m_deviceInterface->getDeviceMemoryOpaqueCaptureAddress(*m_device, &memoryOpaqueCaptureAddressInfo);
4005     }
4006 
4007     VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *bufferResource.buffer, bufferResource.alloc->getMemory(),
4008                                                  bufferResource.alloc->getOffset()));
4009 
4010     bufferResource.loadDeviceAddress(*m_deviceInterface, *m_device);
4011 }
4012 
createImageForBinding(ResourceHolder & resources,VkDescriptorType descriptorType) const4013 void DescriptorBufferTestInstance::createImageForBinding(ResourceHolder &resources,
4014                                                          VkDescriptorType descriptorType) const
4015 {
4016     auto &imageResource = resources.image;
4017 
4018     // Image
4019     auto &captureReplayData = resources.captureReplay.imageData;
4020 
4021     if (isCaptureDescriptor(descriptorType))
4022     {
4023         imageResource.info.flags |= VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4024 
4025         DE_ASSERT(!imageResource.image);
4026         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4027 
4028         VkImageCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4029         info.image                               = *imageResource.image;
4030 
4031         DE_ASSERT(captureReplayData.empty());
4032         captureReplayData.resize(m_descriptorBufferProperties.imageCaptureReplayDescriptorDataSize);
4033 
4034         VK_CHECK(m_deviceInterface->getImageOpaqueCaptureDescriptorDataEXT(*m_device, &info, captureReplayData.data()));
4035     }
4036     else if (isReplayDescriptor(descriptorType))
4037     {
4038         // Free the previous image, its memory and the image view
4039         reset(imageResource.image);
4040         reset(imageResource.alloc);
4041         reset(imageResource.imageView);
4042 
4043         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
4044         info.opaqueCaptureDescriptorData                = captureReplayData.data();
4045 
4046         imageResource.info.flags |= VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4047         imageResource.info.pNext = &info;
4048 
4049         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4050     }
4051     else
4052     {
4053         DE_ASSERT(!imageResource.image);
4054         imageResource.image = createImage(*m_deviceInterface, *m_device, &imageResource.info);
4055     }
4056 
4057     // Memory allocation
4058     auto memReqs = getImageMemoryRequirements(*m_deviceInterface, *m_device, *imageResource.image);
4059 
4060     VkMemoryOpaqueCaptureAddressAllocateInfo opaqueCaptureAddressAllocateInfo = initVulkanStructure();
4061     VkMemoryAllocateFlagsInfo allocFlagsInfo                                  = initVulkanStructure();
4062 
4063     if (m_params.isCaptureReplayDescriptor(descriptorType))
4064     {
4065         allocFlagsInfo.flags |=
4066             VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT | VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
4067         allocFlagsInfo.pNext = &opaqueCaptureAddressAllocateInfo;
4068 
4069         if (isCaptureDescriptor(descriptorType))
4070         {
4071             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = 0ull;
4072         }
4073         else if (isReplayDescriptor(descriptorType))
4074         {
4075             opaqueCaptureAddressAllocateInfo.opaqueCaptureAddress = imageResource.opaqueCaptureAddress;
4076         }
4077     }
4078 
4079     DE_ASSERT(!imageResource.alloc);
4080     imageResource.sizeBytes = memReqs.size;
4081     imageResource.alloc     = allocate(memReqs, MemoryRequirement::Local, &allocFlagsInfo);
4082 
4083     if (isCaptureDescriptor(descriptorType))
4084     {
4085         VkDeviceMemoryOpaqueCaptureAddressInfo memoryOpaqueCaptureAddressInfo = initVulkanStructure();
4086 
4087         memoryOpaqueCaptureAddressInfo.memory = imageResource.alloc->getMemory();
4088 
4089         imageResource.opaqueCaptureAddress =
4090             m_deviceInterface->getDeviceMemoryOpaqueCaptureAddress(*m_device, &memoryOpaqueCaptureAddressInfo);
4091     }
4092 
4093     VK_CHECK(m_deviceInterface->bindImageMemory(*m_device, *imageResource.image, imageResource.alloc->getMemory(),
4094                                                 imageResource.alloc->getOffset()));
4095 
4096     // Image view
4097     {
4098         auto &captureReplayDataView = resources.captureReplay.imageViewData;
4099 
4100         DE_ASSERT(imageResource.info.imageType == VK_IMAGE_TYPE_2D);
4101 
4102         VkImageViewCreateInfo createInfo = initVulkanStructure();
4103         createInfo.image                 = *imageResource.image;
4104         createInfo.viewType              = VK_IMAGE_VIEW_TYPE_2D;
4105         createInfo.format                = imageResource.info.format;
4106         createInfo.components            = ComponentMappingIdentity;
4107         createInfo.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
4108 
4109         if (isCaptureDescriptor(descriptorType))
4110         {
4111             createInfo.flags |= VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4112 
4113             DE_ASSERT(!imageResource.imageView);
4114             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4115 
4116             VkImageViewCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4117             info.imageView                               = *imageResource.imageView;
4118 
4119             DE_ASSERT(captureReplayDataView.empty());
4120             captureReplayDataView.resize(m_descriptorBufferProperties.imageViewCaptureReplayDescriptorDataSize);
4121 
4122             VK_CHECK(m_deviceInterface->getImageViewOpaqueCaptureDescriptorDataEXT(*m_device, &info,
4123                                                                                    captureReplayDataView.data()));
4124         }
4125         else if (isReplayDescriptor(descriptorType))
4126         {
4127             VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
4128             info.opaqueCaptureDescriptorData                = captureReplayDataView.data();
4129 
4130             createInfo.flags |= VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
4131             createInfo.pNext = &info;
4132 
4133             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4134         }
4135         else
4136         {
4137             VkSamplerYcbcrConversionInfo samplerYcbcrConvInfo = initVulkanStructure();
4138 
4139             if (resources.samplerYcbcrConversion)
4140             {
4141                 DE_ASSERT(m_params.variant == TestVariant::YCBCR_SAMPLER);
4142 
4143                 samplerYcbcrConvInfo.conversion = *resources.samplerYcbcrConversion;
4144 
4145                 createInfo.pNext = &samplerYcbcrConvInfo;
4146             }
4147 
4148             // No assertion here, as we must create a new view to go with the image.
4149             imageResource.imageView = createImageView(*m_deviceInterface, *m_device, &createInfo);
4150         }
4151     }
4152 }
4153 
4154 // This function prepares a descriptor binding for use:
4155 // - Create necessary buffer/image resources and initialize them
4156 // - Write descriptor data into the descriptor buffer
4157 // - Fix the memory layout of combined image samplers (if needed)
4158 //
initializeBinding(const DescriptorSetLayoutHolder & dsl,uint32_t setIndex,Binding & binding)4159 void DescriptorBufferTestInstance::initializeBinding(const DescriptorSetLayoutHolder &dsl, uint32_t setIndex,
4160                                                      Binding &binding)
4161 {
4162     const auto arrayCount =
4163         (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) ? 1 : binding.descriptorCount;
4164 
4165     const bool mustSplitCombinedImageSampler =
4166         (arrayCount > 1) && (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
4167         (m_descriptorBufferProperties.combinedImageSamplerDescriptorSingleArray == VK_FALSE);
4168 
4169     const bool isRobustBufferAccess = (m_params.variant == TestVariant::ROBUST_BUFFER_ACCESS);
4170     const bool isNullDescriptor     = (m_params.variant == TestVariant::ROBUST_NULL_DESCRIPTOR) &&
4171                                   (binding.descriptorType == m_params.descriptor) && binding.isTestableDescriptor();
4172 
4173     for (uint32_t arrayIndex = 0; arrayIndex < arrayCount; ++arrayIndex)
4174     {
4175         VkDescriptorGetInfoEXT descGetInfo     = initVulkanStructure();
4176         VkDescriptorAddressInfoEXT addressInfo = initVulkanStructure();
4177         VkDescriptorImageInfo imageInfo{
4178             0, 0, VK_IMAGE_LAYOUT_UNDEFINED}; // must be explicitly initialized due to CTS handles inside
4179 
4180         descGetInfo.type = VK_DESCRIPTOR_TYPE_MAX_ENUM;
4181 
4182         if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
4183             (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER))
4184         {
4185             auto &resources      = getOrCreateResource(binding, arrayIndex);
4186             auto &bufferResource = resources.buffer;
4187 
4188             const VkBufferUsageFlags usage =
4189                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT :
4190                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT :
4191                                                                                 0;
4192             DE_ASSERT(usage);
4193 
4194             bufferResource.size =
4195                 sizeof(uint32_t) * (binding.isResultBuffer ? ConstResultBufferDwords : ConstUniformBufferDwords);
4196 
4197             createBufferForBinding(resources, binding.descriptorType, makeBufferCreateInfo(bufferResource.size, usage),
4198                                    binding.isResultBuffer);
4199 
4200             uint32_t *pBufferData = static_cast<uint32_t *>(bufferResource.alloc->getHostPtr());
4201 
4202             if (binding.isResultBuffer || isRobustBufferAccess)
4203             {
4204                 // We zero the buffer if it's a result buffer or if it's used with robust access.
4205                 deMemset(pBufferData, 0, static_cast<std::size_t>(bufferResource.size));
4206             }
4207             else
4208             {
4209                 const auto data = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4210 
4211                 for (uint32_t i = 0; i < ConstUniformBufferDwords; ++i)
4212                 {
4213                     pBufferData[i] = data + i;
4214                 }
4215             }
4216 
4217             addressInfo.address = bufferResource.deviceAddress;
4218             addressInfo.range   = bufferResource.size;
4219             addressInfo.format  = VK_FORMAT_UNDEFINED;
4220 
4221             DE_UNREF(ConstRobustBufferAlignment);
4222             DE_ASSERT(binding.isResultBuffer || !isRobustBufferAccess ||
4223                       ((addressInfo.range % ConstRobustBufferAlignment) == 0));
4224 
4225             descGetInfo.type                = binding.descriptorType;
4226             descGetInfo.data.pUniformBuffer = isNullDescriptor ? nullptr : &addressInfo; // and pStorageBuffer
4227         }
4228         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4229         {
4230             // Inline uniforms don't use a backing buffer.
4231             DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID);
4232         }
4233         else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
4234                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
4235         {
4236             auto &resources      = getOrCreateResource(binding, arrayIndex);
4237             auto &bufferResource = resources.buffer;
4238 
4239             const VkBufferUsageFlags usage = (binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ?
4240                                                  VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT :
4241                                              (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ?
4242                                                  VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT :
4243                                                  0;
4244             DE_ASSERT(usage);
4245 
4246             bufferResource.size = ConstTexelBufferElements * sizeof(uint32_t);
4247 
4248             createBufferForBinding(resources, binding.descriptorType, makeBufferCreateInfo(bufferResource.size, usage),
4249                                    binding.isResultBuffer);
4250 
4251             if (m_params.isPushDescriptorTest())
4252             {
4253                 // Push descriptors use buffer views.
4254                 auto &bufferViewResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).bufferView;
4255 
4256                 bufferViewResource = makeBufferView(*m_deviceInterface, *m_device, *bufferResource.buffer,
4257                                                     VK_FORMAT_R32_UINT, 0, bufferResource.size);
4258             }
4259 
4260             uint32_t *pBufferData = static_cast<uint32_t *>(bufferResource.alloc->getHostPtr());
4261 
4262             if (isRobustBufferAccess)
4263             {
4264                 // Zero the buffer used with robust access.
4265                 deMemset(pBufferData, 0, static_cast<std::size_t>(bufferResource.size));
4266             }
4267             else
4268             {
4269                 const auto data = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4270 
4271                 for (uint32_t i = 0; i < ConstTexelBufferElements; ++i)
4272                 {
4273                     pBufferData[i] = data + i;
4274                 }
4275             }
4276 
4277             addressInfo.address = bufferResource.deviceAddress;
4278             addressInfo.range   = bufferResource.size;
4279             addressInfo.format  = VK_FORMAT_R32_UINT;
4280 
4281             DE_UNREF(ConstRobustBufferAlignment);
4282             DE_ASSERT(!isRobustBufferAccess || ((addressInfo.range % ConstRobustBufferAlignment) == 0));
4283 
4284             descGetInfo.type                     = binding.descriptorType;
4285             descGetInfo.data.pUniformTexelBuffer = isNullDescriptor ? nullptr : &addressInfo; // and pStorageTexelBuffer
4286         }
4287         else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
4288                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
4289                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
4290                  (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
4291         {
4292             // Check if we had already added the resource while handling samplers.
4293             auto &resources     = getOrCreateResource(binding, arrayIndex);
4294             auto &imageResource = resources.image;
4295             auto &stagingBuffer = resources.buffer;
4296 
4297             {
4298                 VkImageLayout layout    = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
4299                 VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
4300 
4301                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
4302                 {
4303                     usage |= VK_IMAGE_USAGE_STORAGE_BIT;
4304                     layout = VK_IMAGE_LAYOUT_GENERAL;
4305                 }
4306                 else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
4307                 {
4308                     usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
4309                 }
4310                 else
4311                 {
4312                     usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
4313                 }
4314 
4315                 // We ensure the extent matches the render area, for the sake of input attachment case.
4316                 imageResource.info                       = initVulkanStructure();
4317                 imageResource.info.flags                 = 0;
4318                 imageResource.info.imageType             = VK_IMAGE_TYPE_2D;
4319                 imageResource.info.format                = m_imageColorFormat;
4320                 imageResource.info.extent.width          = m_renderArea.extent.width;
4321                 imageResource.info.extent.height         = m_renderArea.extent.height;
4322                 imageResource.info.extent.depth          = 1;
4323                 imageResource.info.mipLevels             = 1;
4324                 imageResource.info.arrayLayers           = 1;
4325                 imageResource.info.samples               = VK_SAMPLE_COUNT_1_BIT;
4326                 imageResource.info.tiling                = VK_IMAGE_TILING_OPTIMAL;
4327                 imageResource.info.usage                 = usage;
4328                 imageResource.info.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4329                 imageResource.info.queueFamilyIndexCount = 0;
4330                 imageResource.info.pQueueFamilyIndices   = nullptr;
4331                 imageResource.info.initialLayout         = VK_IMAGE_LAYOUT_UNDEFINED;
4332 
4333                 createImageForBinding(resources, binding.descriptorType);
4334 
4335                 imageResource.layout = layout;
4336 
4337                 imageInfo.imageLayout = layout;
4338                 imageInfo.imageView   = *imageResource.imageView;
4339 
4340                 descGetInfo.type = binding.descriptorType;
4341 
4342                 if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
4343                 {
4344                     if (isNullDescriptor)
4345                         imageInfo.imageView = DE_NULL;
4346 
4347                     descGetInfo.data.pCombinedImageSampler = &imageInfo;
4348                 }
4349                 else
4350                     descGetInfo.data.pStorageImage = isNullDescriptor ? nullptr : &imageInfo;
4351             }
4352             {
4353                 const auto numPixels = m_renderArea.extent.width * m_renderArea.extent.height; // plane 0
4354 
4355                 if (m_imageColorFormat == VK_FORMAT_R32_UINT)
4356                 {
4357                     stagingBuffer.size = sizeof(uint32_t) * numPixels;
4358                 }
4359                 else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
4360                 {
4361                     DE_ASSERT((m_renderArea.extent.width % 2) == 0);
4362                     DE_ASSERT((m_renderArea.extent.height % 2) == 0);
4363 
4364                     stagingBuffer.size = 1 * numPixels;      // g8
4365                     stagingBuffer.size += 2 * numPixels / 4; // b8r8
4366                 }
4367                 else
4368                 {
4369                     DE_ASSERT(0);
4370                 }
4371 
4372                 auto createInfo = makeBufferCreateInfo(stagingBuffer.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
4373 
4374                 stagingBuffer.buffer = createBuffer(*m_deviceInterface, *m_device, &createInfo);
4375 
4376                 auto memReqs = getBufferMemoryRequirements(*m_deviceInterface, *m_device, *stagingBuffer.buffer);
4377 
4378                 stagingBuffer.alloc = allocate(memReqs, MemoryRequirement::HostVisible);
4379 
4380                 VK_CHECK(m_deviceInterface->bindBufferMemory(*m_device, *stagingBuffer.buffer,
4381                                                              stagingBuffer.alloc->getMemory(),
4382                                                              stagingBuffer.alloc->getOffset()));
4383 
4384                 // Fill the whole image uniformly
4385                 if (m_imageColorFormat == VK_FORMAT_R32_UINT)
4386                 {
4387                     auto pBufferData = static_cast<uint32_t *>(stagingBuffer.alloc->getHostPtr());
4388                     uint32_t expectedData;
4389 
4390                     if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
4391                     {
4392                         expectedData = getExpectedData(m_params.hash, setIndex, binding.binding,
4393                                                        binding.inputAttachmentIndex + arrayIndex);
4394                     }
4395                     else
4396                     {
4397                         expectedData = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4398                     }
4399 
4400                     std::fill(pBufferData, pBufferData + numPixels, expectedData);
4401                 }
4402                 else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
4403                 {
4404                     auto pPlane0 = static_cast<uint8_t *>(stagingBuffer.alloc->getHostPtr());
4405                     auto pPlane1 = static_cast<uint16_t *>(offsetPtr(pPlane0, numPixels));
4406                     const auto expectedData =
4407                         getExpectedData_G8_B8R8(m_params.hash, setIndex, binding.binding, arrayIndex);
4408 
4409                     std::fill(pPlane0, pPlane0 + numPixels, expectedData.x());
4410                     std::fill(pPlane1, pPlane1 + numPixels / 4, expectedData.y());
4411                 }
4412                 else
4413                 {
4414                     DE_ASSERT(0);
4415                 }
4416             }
4417 
4418             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
4419             {
4420                 DE_ASSERT(m_params.variant != TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS);
4421 
4422                 DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4423                 auto &resourceSampler = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4424 
4425                 imageInfo.sampler = *resourceSampler;
4426             }
4427         }
4428         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER)
4429         {
4430             if (m_params.variant != TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS)
4431             {
4432                 DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4433                 auto &resourceSampler = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4434 
4435                 descGetInfo.type          = binding.descriptorType;
4436                 descGetInfo.data.pSampler = &*resourceSampler;
4437             }
4438         }
4439         else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
4440         {
4441             Allocator &allocator        = *m_allocatorPtr;
4442             const uint32_t expectedData = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4443             const float zDepth          = float(expectedData);
4444             const std::vector<tcu::Vec3> vertices{
4445                 tcu::Vec3(-1.0f, -1.0f, zDepth), tcu::Vec3(-1.0f, 1.0f, zDepth), tcu::Vec3(1.0f, -1.0f, zDepth),
4446 
4447                 tcu::Vec3(-1.0f, 1.0f, zDepth),  tcu::Vec3(1.0f, 1.0f, zDepth),  tcu::Vec3(1.0f, -1.0f, zDepth),
4448             };
4449             auto &resources              = getOrCreateResource(binding, arrayIndex);
4450             const bool replayableBinding = binding.isTestableDescriptor();
4451             VkAccelerationStructureCreateFlagsKHR createFlags =
4452                 (m_params.isCaptureReplayDescriptor(binding.descriptorType) && replayableBinding) ?
4453                     static_cast<VkAccelerationStructureCreateFlagsKHR>(
4454                         VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT) :
4455                     static_cast<VkAccelerationStructureCreateFlagsKHR>(0u);
4456             vk::MemoryRequirement memoryReqs =
4457                 (m_params.isCaptureReplayDescriptor(binding.descriptorType) && replayableBinding) ?
4458                     MemoryRequirement::DeviceAddressCaptureReplay :
4459                     MemoryRequirement::Any;
4460             VkOpaqueCaptureDescriptorDataCreateInfoEXT infos[]     = {initVulkanStructure(), initVulkanStructure()};
4461             VkOpaqueCaptureDescriptorDataCreateInfoEXT *infoPtrs[] = {DE_NULL, DE_NULL};
4462 
4463             if (isReplayDescriptor(binding.descriptorType) && replayableBinding)
4464             {
4465                 resources.rtBlas.clear();
4466                 resources.rtTlas.clear();
4467 
4468                 std::vector<uint8_t> *captureReplayDatas[] = {&resources.captureReplay.accelerationStructureDataBlas,
4469                                                               &resources.captureReplay.accelerationStructureDataTlas};
4470 
4471                 for (int ndx = 0; ndx < 2; ++ndx)
4472                 {
4473                     std::vector<uint8_t> &captureReplayData          = *captureReplayDatas[ndx];
4474                     VkOpaqueCaptureDescriptorDataCreateInfoEXT &info = infos[ndx];
4475 
4476                     info.opaqueCaptureDescriptorData = captureReplayData.data();
4477                     infoPtrs[ndx]                    = &infos[ndx];
4478                 }
4479             }
4480 
4481             {
4482                 DE_ASSERT(resources.rtBlas.get() == DE_NULL);
4483 
4484                 resources.rtBlas =
4485                     de::SharedPtr<BottomLevelAccelerationStructure>(makeBottomLevelAccelerationStructure().release());
4486                 if (binding.isRayTracingAS)
4487                     resources.rtBlas->setDefaultGeometryData(m_params.stage);
4488                 else
4489                     resources.rtBlas->setGeometryData(vertices, true);
4490                 resources.rtBlas->setCreateFlags(createFlags);
4491                 resources.rtBlas->create(*m_deviceInterface, *m_device, allocator, 0, 0, infoPtrs[0], memoryReqs);
4492             }
4493 
4494             {
4495                 DE_ASSERT(resources.rtTlas.get() == DE_NULL);
4496 
4497                 resources.rtTlas = makeTopLevelAccelerationStructure();
4498                 resources.rtTlas->addInstance(resources.rtBlas);
4499                 resources.rtTlas->setCreateFlags(createFlags);
4500                 resources.rtTlas->create(*m_deviceInterface, *m_device, allocator, 0, 0, infoPtrs[1], memoryReqs);
4501             }
4502 
4503             if (isCaptureDescriptor(binding.descriptorType) && replayableBinding)
4504             {
4505                 const VkAccelerationStructureKHR *accelerationStructures[] = {resources.rtBlas->getPtr(),
4506                                                                               resources.rtTlas->getPtr()};
4507                 std::vector<uint8_t> *captureReplayDatas[] = {&resources.captureReplay.accelerationStructureDataBlas,
4508                                                               &resources.captureReplay.accelerationStructureDataTlas};
4509 
4510                 for (int ndx = 0; ndx < 2; ++ndx)
4511                 {
4512                     VkAccelerationStructureCaptureDescriptorDataInfoEXT info = initVulkanStructure();
4513                     const VkAccelerationStructureKHR *accelerationStructure  = accelerationStructures[ndx];
4514                     std::vector<uint8_t> &captureReplayData                  = *captureReplayDatas[ndx];
4515 
4516                     DE_ASSERT(accelerationStructure != DE_NULL && *accelerationStructure != DE_NULL);
4517                     DE_ASSERT(captureReplayData.empty());
4518 
4519                     info.accelerationStructure = *accelerationStructure;
4520 
4521                     captureReplayData.resize(
4522                         m_descriptorBufferProperties.accelerationStructureCaptureReplayDescriptorDataSize);
4523 
4524                     VK_CHECK(m_deviceInterface->getAccelerationStructureOpaqueCaptureDescriptorDataEXT(
4525                         *m_device, &info, captureReplayData.data()));
4526                 }
4527             }
4528 
4529             descGetInfo.type = binding.descriptorType;
4530             descGetInfo.data.accelerationStructure =
4531                 isNullDescriptor ?
4532                     DE_NULL :
4533                     getAccelerationStructureDeviceAddress(*m_deviceInterface, *m_device, *resources.rtTlas->getPtr());
4534         }
4535         else
4536         {
4537             TCU_THROW(InternalError, "Not implemented");
4538         }
4539 
4540         if (dsl.usePushDescriptors || dsl.sizeOfLayout == 0)
4541         {
4542             // Push descriptors don't rely on descriptor buffers, move to the next binding.
4543             continue;
4544         }
4545 
4546         // Write the descriptor at the right offset in the descriptor buffer memory.
4547         // - With inline uniform blocks, we write the uniform data into the descriptor buffer directly.
4548         // - With regular descriptors, the written memory is opaque to us (same goes for null descriptors).
4549         {
4550             void *bindingHostPtr = nullptr;
4551             Allocation *pAlloc   = nullptr;
4552             auto arrayOffset     = arrayIndex * getDescriptorSize(binding);
4553 
4554             if (dsl.stagingBufferOffset == OFFSET_UNUSED)
4555             {
4556                 const auto &descriptorBuffer = *m_descriptorBuffers[dsl.bufferIndex];
4557                 const auto bufferHostPtr     = offsetPtr(descriptorBuffer.alloc->getHostPtr(), dsl.bufferOffset);
4558 
4559                 bindingHostPtr = offsetPtr(bufferHostPtr, binding.offset);
4560                 pAlloc         = descriptorBuffer.alloc.get();
4561             }
4562             else
4563             {
4564                 bindingHostPtr =
4565                     offsetPtr(m_descriptorStagingBuffer.alloc->getHostPtr(), dsl.stagingBufferOffset + binding.offset);
4566 
4567                 pAlloc = m_descriptorStagingBuffer.alloc.get();
4568             }
4569 
4570             if (binding.descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4571             {
4572                 DE_ASSERT(arrayIndex == 0);
4573 
4574                 // Inline uniform data is written in descriptor buffer directly.
4575                 const auto numDwords = binding.descriptorCount / sizeof(uint32_t);
4576                 const auto data      = getExpectedData(m_params.hash, setIndex, binding.binding, arrayIndex);
4577 
4578                 uint32_t *pInlineData = static_cast<uint32_t *>(bindingHostPtr);
4579 
4580                 for (uint32_t i = 0; i < numDwords; ++i)
4581                 {
4582                     pInlineData[i] = data + i;
4583                 }
4584             }
4585             else if (isReplayDescriptor(binding.descriptorType))
4586             {
4587                 // We're expecting that a descriptor based on replayed resources will have exactly the same binary data.
4588                 // Copy it and compare after obtaining the new descriptor.
4589                 //
4590                 auto descriptorPtr        = offsetPtr(bindingHostPtr, arrayOffset);
4591                 const auto descriptorSize = static_cast<size_t>(getDescriptorSize(binding));
4592 
4593                 std::vector<uint8_t> reference(descriptorSize);
4594                 deMemcpy(reference.data(), descriptorPtr, descriptorSize);
4595 
4596                 deMemset(descriptorPtr, 0xcc, descriptorSize);
4597                 m_deviceInterface->getDescriptorEXT(*m_device, &descGetInfo, descriptorSize, descriptorPtr);
4598 
4599                 if (deMemCmp(reference.data(), descriptorPtr, descriptorSize) != 0)
4600                 {
4601                     TCU_THROW(TestError, "Replayed descriptor differs from the captured descriptor");
4602                 }
4603             }
4604             else
4605             {
4606                 auto descriptorPtr        = offsetPtr(bindingHostPtr, arrayOffset);
4607                 const auto descriptorSize = static_cast<size_t>(getDescriptorSize(binding));
4608                 m_deviceInterface->getDescriptorEXT(*m_device, &descGetInfo, descriptorSize, descriptorPtr);
4609             }
4610 
4611             // After writing the last array element, rearrange the split combined image sampler data.
4612             if (mustSplitCombinedImageSampler && ((arrayIndex + 1) == arrayCount))
4613             {
4614                 // We determined the size of the descriptor set layout on the VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type,
4615                 // so it's expected the following holds true.
4616                 DE_ASSERT((m_descriptorBufferProperties.sampledImageDescriptorSize +
4617                            m_descriptorBufferProperties.samplerDescriptorSize) ==
4618                           m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4619 
4620                 std::vector<uint8_t> scratchSpace(arrayCount *
4621                                                   m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4622 
4623                 const auto descriptorArraySize = static_cast<std::size_t>(
4624                     arrayCount * m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4625 
4626                 deMemcpy(scratchSpace.data(), bindingHostPtr, descriptorArraySize);
4627                 deMemset(bindingHostPtr, 0, descriptorArraySize);
4628 
4629                 const void *combinedReadPtr = scratchSpace.data();
4630                 void *imageWritePtr         = bindingHostPtr;
4631                 void *samplerWritePtr =
4632                     offsetPtr(bindingHostPtr, arrayCount * m_descriptorBufferProperties.sampledImageDescriptorSize);
4633 
4634                 for (uint32_t i = 0; i < arrayCount; ++i)
4635                 {
4636                     deMemcpy(imageWritePtr, offsetPtr(combinedReadPtr, 0),
4637                              m_descriptorBufferProperties.sampledImageDescriptorSize);
4638                     deMemcpy(samplerWritePtr,
4639                              offsetPtr(combinedReadPtr, m_descriptorBufferProperties.sampledImageDescriptorSize),
4640                              m_descriptorBufferProperties.samplerDescriptorSize);
4641 
4642                     combinedReadPtr =
4643                         offsetPtr(combinedReadPtr, m_descriptorBufferProperties.combinedImageSamplerDescriptorSize);
4644                     imageWritePtr   = offsetPtr(imageWritePtr, m_descriptorBufferProperties.sampledImageDescriptorSize);
4645                     samplerWritePtr = offsetPtr(samplerWritePtr, m_descriptorBufferProperties.samplerDescriptorSize);
4646                 }
4647             }
4648 
4649             flushAlloc(*m_deviceInterface, *m_device, *pAlloc);
4650         }
4651     }
4652 }
4653 
4654 // Update a descriptor set with a push or a push template.
4655 //
pushDescriptorSet(VkCommandBuffer cmdBuf,VkPipelineBindPoint bindPoint,const DescriptorSetLayoutHolder & dsl,uint32_t setIndex) const4656 void DescriptorBufferTestInstance::pushDescriptorSet(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPoint,
4657                                                      const DescriptorSetLayoutHolder &dsl, uint32_t setIndex) const
4658 {
4659     std::vector<PushDescriptorData> descriptorData(dsl.bindings.size()); // Allocate empty elements upfront
4660     std::vector<VkWriteDescriptorSet> descriptorWrites;
4661     std::vector<VkWriteDescriptorSetAccelerationStructureKHR> descriptorWritesAccelerationStructures;
4662 
4663     descriptorWrites.reserve(dsl.bindings.size());
4664     descriptorWritesAccelerationStructures.reserve(dsl.bindings.size());
4665 
4666     // Fill in the descriptor data structure. It can be used by the regular and templated update path.
4667 
4668     for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
4669     {
4670         const auto &binding = dsl.bindings[bindingIndex];
4671 
4672         VkWriteDescriptorSet write = initVulkanStructure();
4673         write.dstSet               = DE_NULL; // ignored with push descriptors
4674         write.dstBinding           = bindingIndex;
4675         write.dstArrayElement      = 0;
4676         write.descriptorCount      = binding.descriptorCount;
4677         write.descriptorType       = binding.descriptorType;
4678 
4679         for (uint32_t arrayIndex = 0; arrayIndex < write.descriptorCount; ++arrayIndex)
4680         {
4681             DE_ASSERT(binding.perBindingResourceIndex[arrayIndex] != INDEX_INVALID);
4682 
4683             if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
4684                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER))
4685             {
4686                 const auto &bufferResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).buffer;
4687 
4688                 auto pInfo    = &descriptorData[bindingIndex].bufferInfos[arrayIndex];
4689                 pInfo->buffer = *bufferResource.buffer;
4690                 pInfo->offset = 0;
4691                 pInfo->range  = bufferResource.size;
4692 
4693                 if (arrayIndex == 0)
4694                 {
4695                     write.pBufferInfo = pInfo;
4696                 }
4697             }
4698             else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
4699                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER))
4700             {
4701                 const auto &bufferViewResource =
4702                     (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).bufferView;
4703 
4704                 auto pBufferView = &descriptorData[bindingIndex].texelBufferViews[arrayIndex];
4705                 *pBufferView     = *bufferViewResource;
4706 
4707                 if (arrayIndex == 0)
4708                 {
4709                     write.pTexelBufferView = pBufferView;
4710                 }
4711             }
4712             else if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
4713                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
4714                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
4715                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
4716                      (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER))
4717             {
4718                 const auto &imageResource   = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).image;
4719                 const auto &samplerResource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).sampler;
4720 
4721                 // Dereferencing unused resources will return null handles, so we can treat all these descriptors uniformly.
4722 
4723                 auto pInfo         = &descriptorData[bindingIndex].imageInfos[arrayIndex];
4724                 pInfo->imageView   = *imageResource.imageView;
4725                 pInfo->imageLayout = imageResource.layout;
4726                 pInfo->sampler     = *samplerResource;
4727 
4728                 if (arrayIndex == 0)
4729                 {
4730                     write.pImageInfo = pInfo;
4731                 }
4732             }
4733             else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
4734             {
4735                 const ResourceHolder &resources = **m_resources[binding.perBindingResourceIndex[arrayIndex]];
4736                 const VkAccelerationStructureKHR *accelerationStructurePtr = resources.rtTlas.get()->getPtr();
4737 
4738                 DE_ASSERT(accelerationStructurePtr != DE_NULL && *accelerationStructurePtr != DE_NULL);
4739 
4740                 descriptorData[bindingIndex].accelerationStructures[arrayIndex] = *accelerationStructurePtr;
4741 
4742                 if (arrayIndex == 0)
4743                 {
4744                     VkWriteDescriptorSetAccelerationStructureKHR descriptorWritesAccelerationStructure =
4745                         initVulkanStructure();
4746 
4747                     descriptorWritesAccelerationStructure.accelerationStructureCount = write.descriptorCount;
4748                     descriptorWritesAccelerationStructure.pAccelerationStructures =
4749                         descriptorData[bindingIndex].accelerationStructures;
4750 
4751                     descriptorWritesAccelerationStructures.emplace_back(descriptorWritesAccelerationStructure);
4752 
4753                     write.pNext =
4754                         &descriptorWritesAccelerationStructures[descriptorWritesAccelerationStructures.size() - 1];
4755                 }
4756             }
4757             else
4758             {
4759                 TCU_THROW(InternalError, "Not implemented");
4760             }
4761         }
4762 
4763         if (m_params.variant == TestVariant::PUSH_DESCRIPTOR)
4764         {
4765             descriptorWrites.emplace_back(write);
4766         }
4767     }
4768 
4769     if (m_params.variant == TestVariant::PUSH_DESCRIPTOR)
4770     {
4771         if (m_params.commands2)
4772         {
4773             vk::VkPushDescriptorSetInfoKHR pushDescriptorSetInfo = {
4774                 VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_INFO_KHR, // VkStructureType sType;
4775                 DE_NULL,                                        // const void* pNext;
4776                 (VkShaderStageFlags)m_params.stage,             // VkShaderStageFlags stageFlags;
4777                 *m_pipelineLayout,                              // VkPipelineLayout layout;
4778                 setIndex,                                       // uint32_t set;
4779                 u32(descriptorWrites.size()),                   // uint32_t descriptorWriteCount;
4780                 descriptorWrites.data()                         // const VkWriteDescriptorSet* pDescriptorWrites;
4781             };
4782             m_deviceInterface->cmdPushDescriptorSet2KHR(cmdBuf, &pushDescriptorSetInfo);
4783         }
4784         else
4785         {
4786             m_deviceInterface->cmdPushDescriptorSetKHR(cmdBuf, bindPoint, *m_pipelineLayout, setIndex,
4787                                                        u32(descriptorWrites.size()), descriptorWrites.data());
4788         }
4789     }
4790     else if (m_params.variant == TestVariant::PUSH_TEMPLATE)
4791     {
4792         std::vector<VkDescriptorUpdateTemplateEntry> updateEntries(descriptorData.size()); // preallocate
4793 
4794         const auto dataBasePtr = reinterpret_cast<uint8_t *>(descriptorData.data());
4795 
4796         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
4797         {
4798             const auto &binding = dsl.bindings[bindingIndex];
4799             const auto &data    = descriptorData[bindingIndex];
4800 
4801             auto &entry           = updateEntries[bindingIndex];
4802             entry.dstBinding      = binding.binding;
4803             entry.dstArrayElement = 0;
4804             entry.descriptorCount = binding.descriptorCount;
4805             entry.descriptorType  = binding.descriptorType;
4806 
4807             switch (binding.descriptorType)
4808             {
4809             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
4810             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
4811                 entry.offset = basePtrOffsetOf(dataBasePtr, data.bufferInfos);
4812                 entry.stride = sizeof(data.bufferInfos[0]);
4813                 break;
4814 
4815             case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
4816             case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
4817                 entry.offset = basePtrOffsetOf(dataBasePtr, data.texelBufferViews);
4818                 entry.stride = sizeof(data.texelBufferViews[0]);
4819                 break;
4820 
4821             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
4822             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
4823             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
4824             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
4825             case VK_DESCRIPTOR_TYPE_SAMPLER:
4826                 entry.offset = basePtrOffsetOf(dataBasePtr, data.imageInfos);
4827                 entry.stride = sizeof(data.imageInfos[0]);
4828                 break;
4829 
4830             case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
4831                 entry.offset = basePtrOffsetOf(dataBasePtr, data.accelerationStructures);
4832                 entry.stride = sizeof(data.accelerationStructures[0]);
4833                 break;
4834 
4835             default:
4836                 DE_ASSERT(0);
4837                 break;
4838             }
4839         }
4840 
4841         VkDescriptorUpdateTemplateCreateInfo createInfo = initVulkanStructure();
4842         createInfo.templateType                         = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR;
4843         createInfo.descriptorSetLayout                  = *dsl.layout;
4844         createInfo.pipelineBindPoint                    = bindPoint;
4845         createInfo.pipelineLayout                       = *m_pipelineLayout;
4846         createInfo.set                                  = setIndex;
4847         createInfo.descriptorUpdateEntryCount           = u32(updateEntries.size());
4848         createInfo.pDescriptorUpdateEntries             = updateEntries.data();
4849 
4850         auto descriptorUpdateTemplate = createDescriptorUpdateTemplate(*m_deviceInterface, *m_device, &createInfo);
4851 
4852         if (m_params.commands2)
4853         {
4854             vk::VkPushDescriptorSetWithTemplateInfoKHR pushDescriptorSetWithTemplateInfo = {
4855                 VK_STRUCTURE_TYPE_PUSH_DESCRIPTOR_SET_WITH_TEMPLATE_INFO_KHR, // VkStructureType sType;
4856                 DE_NULL,                                                      // const void* pNext;
4857                 *descriptorUpdateTemplate, // VkDescriptorUpdateTemplate descriptorUpdateTemplate;
4858                 *m_pipelineLayout,         // VkPipelineLayout layout;
4859                 setIndex,                  // uint32_t set;
4860                 dataBasePtr                // const void* pData;
4861             };
4862             m_deviceInterface->cmdPushDescriptorSetWithTemplate2KHR(cmdBuf, &pushDescriptorSetWithTemplateInfo);
4863         }
4864         else
4865         {
4866             m_deviceInterface->cmdPushDescriptorSetWithTemplateKHR(cmdBuf, *descriptorUpdateTemplate, *m_pipelineLayout,
4867                                                                    setIndex, dataBasePtr);
4868         }
4869     }
4870 }
4871 
4872 // Perform the test accoring to the parameters. At high level, all tests perform these steps:
4873 //
4874 // - Create a new device and queues, query extension properties.
4875 // - Fill descriptor set layouts and bindings, based on SimpleBinding's.
4876 // - Create samplers, if needed. Set immutable samplers in bindings.
4877 // - Create descriptor set layouts.
4878 //   - If mutable descriptor types are used, it affects: descriptor size and offset and descriptor set layout creation.
4879 //     However, the rest of the logic is largely unchanged and refers to the specific descriptor type used at runtime.
4880 // - Create descriptor buffers.
4881 // - Iterate over all bindings to:
4882 //   - Create their resources (images, buffers) and initialize them
4883 //   - Write bindings to descriptor buffer memory
4884 //   - Fix combined image samplers for arrayed bindings (if applicable)
4885 // - Create the pipeline layout, shaders, and the pipeline
4886 // - Create the command buffer and record the commands (barriers omitted for brevity):
4887 //   - Bind the pipeline and the descriptor buffers
4888 //   - Upload descriptor buffer data (with staged uploads)
4889 //   - Upload image data (if images are used)
4890 //   - Push descriptors (if used)
4891 //   - Dispatch or draw
4892 //   - Submit the commands
4893 //   - Map the result buffer to a host pointer
4894 //   - Verify the result and log diagnostic on a failure
4895 //
4896 // Verification logic is very simple.
4897 //
4898 // Each successful binding read will increment the result counter. If the shader got an unexpected value, the counter
4899 // will be less than expected. Additionally, the first failed set/binding/array index will be recorded.
4900 //
4901 // With capture/replay tests, iterate() will be called twice, splitting the test into capture and replay passes.
4902 // The capture pass saves the opaque data, while the replay pass uses it and compares the results.
4903 //
iterate()4904 tcu::TestStatus DescriptorBufferTestInstance::iterate()
4905 {
4906     DE_ASSERT(m_params.bufferBindingCount <= m_descriptorBufferProperties.maxDescriptorBufferBindings);
4907 
4908     const auto &vk = *m_deviceInterface;
4909 
4910     if (m_testIteration == 0)
4911     {
4912         uint32_t currentSet = INDEX_INVALID;
4913 
4914         uint32_t inlineUniformSize = 0u;
4915 
4916         for (const auto &sb : m_simpleBindings)
4917         {
4918             if ((currentSet == INDEX_INVALID) || (currentSet < sb.set))
4919             {
4920                 currentSet = sb.set;
4921 
4922                 addDescriptorSetLayout();
4923             }
4924 
4925             auto &dsl                     = **m_descriptorSetLayouts.back();
4926             VkShaderStageFlags stageFlags = sb.isRayTracingAS ?
4927                                                 static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_RAYGEN_BIT_KHR) :
4928                                                 static_cast<VkShaderStageFlags>(0u);
4929 
4930             Binding binding{};
4931             binding.binding              = sb.binding;
4932             binding.descriptorType       = sb.type;
4933             binding.stageFlags           = m_params.stage | stageFlags;
4934             binding.inputAttachmentIndex = sb.inputAttachmentIndex;
4935             binding.isResultBuffer       = sb.isResultBuffer;
4936             binding.isRayTracingAS       = sb.isRayTracingAS;
4937             binding.isMutableType        = (m_params.variant == TestVariant::MUTABLE_DESCRIPTOR_TYPE) &&
4938                                     sb.type != VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR &&
4939                                     maskCheck(m_params.mutableDescriptorTypes, sb.type);
4940 
4941             if (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
4942             {
4943                 binding.descriptorCount = sizeof(uint32_t) * ConstInlineBlockDwords;
4944                 inlineUniformSize += binding.descriptorCount;
4945             }
4946             else
4947             {
4948                 binding.descriptorCount = sb.count;
4949             }
4950 
4951             if ((sb.type == VK_DESCRIPTOR_TYPE_SAMPLER) || (sb.type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
4952             {
4953                 if (sb.isEmbeddedImmutableSampler)
4954                 {
4955                     dsl.hasEmbeddedImmutableSamplers = true;
4956                 }
4957             }
4958 
4959             if (m_params.isPushDescriptorTest() &&
4960                 (m_params.pushDescriptorSetIndex == (m_descriptorSetLayouts.size() - 1)))
4961             {
4962                 dsl.usePushDescriptors = true;
4963             }
4964 
4965             dsl.bindings.emplace_back(binding);
4966         }
4967 
4968         const VkPhysicalDeviceVulkan13Properties &vulkan13properties = m_context.getDeviceVulkan13Properties();
4969         if (m_context.getUsedApiVersion() >= VK_API_VERSION_1_3 &&
4970             inlineUniformSize > vulkan13properties.maxInlineUniformTotalSize)
4971         {
4972             TCU_THROW(NotSupportedError, "Test require more inline uniform total size among all stages. Provided " +
4973                                              de::toString(vulkan13properties.maxInlineUniformTotalSize));
4974         }
4975     }
4976 
4977     // We create samplers before creating the descriptor set layouts, in case we need to use
4978     // immutable (or embedded) samplers.
4979 
4980     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
4981     {
4982         auto &dsl = **m_descriptorSetLayouts[setIndex];
4983 
4984         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
4985         {
4986             auto &binding = dsl.bindings[bindingIndex];
4987 
4988             if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
4989                 (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
4990             {
4991                 for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
4992                 {
4993                     if (binding.perBindingResourceIndex[arrayIndex] == INDEX_INVALID)
4994                     {
4995                         binding.perBindingResourceIndex[arrayIndex] = addResource();
4996                     }
4997 
4998                     auto &resources         = **m_resources[binding.perBindingResourceIndex[arrayIndex]];
4999                     auto &captureReplayData = resources.captureReplay.samplerData;
5000 
5001                     if (m_params.variant == TestVariant::YCBCR_SAMPLER)
5002                     {
5003                         VkSamplerYcbcrConversionCreateInfo convCreateInfo = initVulkanStructure();
5004                         convCreateInfo.format                             = m_imageColorFormat;
5005                         convCreateInfo.ycbcrModel                  = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
5006                         convCreateInfo.ycbcrRange                  = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
5007                         convCreateInfo.components                  = ComponentMappingIdentity;
5008                         convCreateInfo.xChromaOffset               = VK_CHROMA_LOCATION_COSITED_EVEN;
5009                         convCreateInfo.yChromaOffset               = VK_CHROMA_LOCATION_COSITED_EVEN;
5010                         convCreateInfo.chromaFilter                = VK_FILTER_NEAREST;
5011                         convCreateInfo.forceExplicitReconstruction = VK_FALSE;
5012 
5013                         resources.samplerYcbcrConversion = createSamplerYcbcrConversion(vk, *m_device, &convCreateInfo);
5014                     }
5015 
5016                     // Use CLAMP_TO_BORDER to verify that sampling outside the image will make use of the sampler's
5017                     // properties. The border color used must match the one in glslOutputVerification().
5018 
5019                     VkSamplerCreateInfo createInfo     = initVulkanStructure();
5020                     createInfo.magFilter               = VK_FILTER_NEAREST;
5021                     createInfo.minFilter               = VK_FILTER_NEAREST;
5022                     createInfo.mipmapMode              = VK_SAMPLER_MIPMAP_MODE_NEAREST;
5023                     createInfo.addressModeU            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5024                     createInfo.addressModeV            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5025                     createInfo.addressModeW            = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
5026                     createInfo.mipLodBias              = 0.0f;
5027                     createInfo.anisotropyEnable        = VK_FALSE;
5028                     createInfo.maxAnisotropy           = 1.0f;
5029                     createInfo.compareEnable           = VK_FALSE;
5030                     createInfo.compareOp               = VK_COMPARE_OP_NEVER;
5031                     createInfo.minLod                  = 0.0;
5032                     createInfo.maxLod                  = 0.0;
5033                     createInfo.borderColor             = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
5034                     createInfo.unnormalizedCoordinates = VK_FALSE;
5035 
5036                     VkSamplerCustomBorderColorCreateInfoEXT customBorderColorInfo = initVulkanStructure();
5037                     VkSamplerYcbcrConversionInfo samplerYcbcrConvInfo             = initVulkanStructure();
5038 
5039                     const void **nextPtr = &createInfo.pNext;
5040 
5041                     if (m_params.variant == TestVariant::YCBCR_SAMPLER)
5042                     {
5043                         createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5044                         createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5045                         createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
5046 
5047                         samplerYcbcrConvInfo.conversion = *resources.samplerYcbcrConversion;
5048 
5049                         addToChainVulkanStructure(&nextPtr, samplerYcbcrConvInfo);
5050                     }
5051 
5052                     if (m_params.subcase == SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR)
5053                     {
5054                         createInfo.borderColor = VK_BORDER_COLOR_INT_CUSTOM_EXT;
5055 
5056                         customBorderColorInfo.format            = VK_FORMAT_R32_UINT;
5057                         customBorderColorInfo.customBorderColor = makeClearValueColorU32(2, 0, 0, 1).color;
5058 
5059                         addToChainVulkanStructure(&nextPtr, customBorderColorInfo);
5060                     }
5061 
5062                     if (isCaptureDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER) ||
5063                         isCaptureDescriptor(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5064                     {
5065                         createInfo.flags |= VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
5066 
5067                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5068 
5069                         VkSamplerCaptureDescriptorDataInfoEXT info = initVulkanStructure();
5070                         info.sampler                               = *resources.sampler;
5071 
5072                         DE_ASSERT(captureReplayData.empty());
5073                         captureReplayData.resize(m_descriptorBufferProperties.samplerCaptureReplayDescriptorDataSize);
5074 
5075                         VK_CHECK(m_deviceInterface->getSamplerOpaqueCaptureDescriptorDataEXT(*m_device, &info,
5076                                                                                              captureReplayData.data()));
5077                     }
5078                     else if (isReplayDescriptor(VK_DESCRIPTOR_TYPE_SAMPLER) ||
5079                              isReplayDescriptor(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5080                     {
5081                         reset(resources.sampler);
5082 
5083                         VkOpaqueCaptureDescriptorDataCreateInfoEXT info = initVulkanStructure();
5084                         info.opaqueCaptureDescriptorData                = captureReplayData.data();
5085 
5086                         createInfo.flags |= VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT;
5087 
5088                         addToChainVulkanStructure(&nextPtr, info);
5089 
5090                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5091                     }
5092                     else
5093                     {
5094                         resources.sampler = createSampler(vk, *m_device, &createInfo);
5095                     }
5096                 }
5097             }
5098         }
5099     }
5100 
5101     if ((m_params.variant == TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS) ||
5102         (m_params.subcase == SubCase::IMMUTABLE_SAMPLERS) || (m_params.variant == TestVariant::YCBCR_SAMPLER))
5103     {
5104         // Patch immutable sampler pointers, now that all memory has been allocated and pointers won't move.
5105 
5106         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5107         {
5108             auto &dsl = **m_descriptorSetLayouts[setIndex];
5109 
5110             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5111             {
5112                 auto &binding = dsl.bindings[bindingIndex];
5113 
5114                 for (uint32_t resourceIndex = 0; resourceIndex < DE_LENGTH_OF_ARRAY(binding.perBindingResourceIndex);
5115                      ++resourceIndex)
5116                 {
5117                     if (binding.perBindingResourceIndex[resourceIndex] != INDEX_INVALID)
5118                     {
5119                         const auto &resources = **m_resources[binding.perBindingResourceIndex[resourceIndex]];
5120 
5121                         if (resources.sampler)
5122                         {
5123                             DE_ASSERT(resourceIndex < DE_LENGTH_OF_ARRAY(binding.immutableSamplers));
5124 
5125                             binding.immutableSamplers[resourceIndex] = *resources.sampler;
5126                         }
5127                     }
5128                 }
5129             }
5130         }
5131     }
5132 
5133     if (m_testIteration == 0)
5134     {
5135         createDescriptorSetLayouts();
5136         createDescriptorBuffers();
5137     }
5138 
5139     for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5140     {
5141         auto &dsl = **m_descriptorSetLayouts[setIndex];
5142 
5143         if (dsl.hasEmbeddedImmutableSamplers)
5144         {
5145             // Embedded samplers are not written to the descriptor buffer directly.
5146             continue;
5147         }
5148 
5149         for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5150         {
5151             auto &binding = dsl.bindings[bindingIndex];
5152 
5153             // The descriptor bindings are initialized in two situations:
5154             // 1. in the first test iteration (which is also the capture pass of capture/replay test)
5155             // 2. in the replay pass, for the binding with the matching descriptor type
5156             //
5157             if ((m_testIteration == 0) ||
5158                 (binding.isTestableDescriptor() && m_params.isCaptureReplayDescriptor(binding.descriptorType)))
5159             {
5160                 initializeBinding(dsl, setIndex, binding);
5161             }
5162         }
5163     }
5164 
5165     {
5166         VkPipelineLayoutCreateInfo createInfo = initVulkanStructure();
5167         const auto dslCopy                    = getDescriptorSetLayouts(m_descriptorSetLayouts);
5168         createInfo.setLayoutCount             = u32(dslCopy.size());
5169         createInfo.pSetLayouts                = dslCopy.data();
5170 
5171         m_pipelineLayout = createPipelineLayout(vk, *m_device, &createInfo);
5172     }
5173 
5174     if (m_params.isCompute())
5175     {
5176         const auto shaderModule = createShaderModule(vk, *m_device, getShaderBinary(VK_SHADER_STAGE_COMPUTE_BIT), 0u);
5177 
5178         const VkPipelineShaderStageCreateInfo pipelineShaderStageParams{
5179             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
5180             nullptr,                                             // const void* pNext;
5181             0u,                                                  // VkPipelineShaderStageCreateFlags flags;
5182             VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
5183             *shaderModule,                                       // VkShaderModule module;
5184             "main",                                              // const char* pName;
5185             nullptr,                                             // const VkSpecializationInfo* pSpecializationInfo;
5186         };
5187         VkComputePipelineCreateInfo pipelineCreateInfo{
5188             VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
5189             nullptr,                                        // const void* pNext;
5190             VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT,   // VkPipelineCreateFlags flags;
5191             pipelineShaderStageParams,                      // VkPipelineShaderStageCreateInfo stage;
5192             *m_pipelineLayout,                              // VkPipelineLayout layout;
5193             DE_NULL,                                        // VkPipeline basePipelineHandle;
5194             0,                                              // int32_t basePipelineIndex;
5195         };
5196 
5197         vk::VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo = vk::initVulkanStructure();
5198         if (m_params.useMaintenance5)
5199         {
5200             pipelineFlags2CreateInfo.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_BUFFER_BIT_EXT;
5201             pipelineCreateInfo.pNext       = &pipelineFlags2CreateInfo;
5202             pipelineCreateInfo.flags       = 0;
5203         }
5204 
5205         m_pipeline = createComputePipeline(vk, *m_device, DE_NULL, &pipelineCreateInfo);
5206     }
5207     else if (m_params.isRayTracing())
5208     {
5209         createRayTracingPipeline();
5210     }
5211     else
5212     {
5213         createGraphicsPipeline();
5214     }
5215 
5216     {
5217         auto cmdPool            = makeCommandPool(vk, *m_device, m_queueFamilyIndex);
5218         auto cmdBuf             = allocateCommandBuffer(vk, *m_device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
5219         const auto bindPoint    = m_params.isCompute()    ? VK_PIPELINE_BIND_POINT_COMPUTE :
5220                                   m_params.isRayTracing() ? VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR :
5221                                   m_params.isGraphics()   ? VK_PIPELINE_BIND_POINT_GRAPHICS :
5222                                                             VK_PIPELINE_BIND_POINT_MAX_ENUM;
5223         const auto dstStageMask = m_params.isCompute()    ? VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT :
5224                                   m_params.isRayTracing() ? VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR :
5225                                   m_params.isGraphics()   ? VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT :
5226                                                             VK_PIPELINE_STAGE_2_NONE;
5227         const auto dstStageMaskUp =
5228             m_params.isCompute()    ? VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT :
5229             m_params.isRayTracing() ? VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR :
5230             m_params.isGraphics()   ? VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT :
5231                                       VK_PIPELINE_STAGE_2_NONE;
5232 
5233         beginCommandBuffer(vk, *cmdBuf);
5234 
5235         vk.cmdBindPipeline(*cmdBuf, bindPoint, *m_pipeline);
5236 
5237         bindDescriptorBuffers(*cmdBuf, bindPoint);
5238 
5239         // Check if we need any staged descriptor set uploads or push descriptors.
5240 
5241         for (uint32_t setIndex = 0; setIndex < m_descriptorSetLayouts.size(); ++setIndex)
5242         {
5243             const auto &dsl = **m_descriptorSetLayouts[setIndex];
5244 
5245             if (dsl.usePushDescriptors)
5246             {
5247                 pushDescriptorSet(*cmdBuf, bindPoint, dsl, setIndex);
5248             }
5249             else if (dsl.stagingBufferOffset != OFFSET_UNUSED)
5250             {
5251                 VkBufferCopy copy{};
5252                 copy.srcOffset = dsl.stagingBufferOffset;
5253                 copy.dstOffset = dsl.bufferOffset;
5254                 copy.size      = dsl.sizeOfLayout;
5255 
5256                 VkBuffer descriptorBuffer = *m_descriptorBuffers[dsl.bufferIndex]->buffer;
5257 
5258                 vk.cmdCopyBuffer(*cmdBuf, *m_descriptorStagingBuffer.buffer, descriptorBuffer,
5259                                  1, // copy regions
5260                                  &copy);
5261 
5262                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5263                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_COPY_BIT;
5264                 barrier.srcAccessMask          = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5265                 barrier.dstStageMask           = dstStageMask;
5266                 barrier.dstAccessMask          = VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT;
5267                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5268                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5269                 barrier.buffer                 = descriptorBuffer;
5270                 barrier.offset                 = 0;
5271                 barrier.size                   = VK_WHOLE_SIZE;
5272 
5273                 VkDependencyInfo depInfo         = initVulkanStructure();
5274                 depInfo.bufferMemoryBarrierCount = 1;
5275                 depInfo.pBufferMemoryBarriers    = &barrier;
5276 
5277                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5278             }
5279         }
5280 
5281         // Upload image data
5282 
5283         for (uint32_t setIndex = 0; setIndex < u32(m_descriptorSetLayouts.size()); ++setIndex)
5284         {
5285             const auto &dsl = **m_descriptorSetLayouts[setIndex];
5286 
5287             for (uint32_t bindingIndex = 0; bindingIndex < u32(dsl.bindings.size()); ++bindingIndex)
5288             {
5289                 const auto &binding = dsl.bindings[bindingIndex];
5290 
5291                 if ((binding.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
5292                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
5293                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) ||
5294                     (binding.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER))
5295                 {
5296                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
5297                     {
5298                         // Need to upload the image data from a staging buffer
5299                         const auto &dstImage  = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).image;
5300                         const auto &srcBuffer = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]).buffer;
5301 
5302                         {
5303                             VkImageMemoryBarrier2 barrier = initVulkanStructure();
5304                             barrier.srcStageMask          = VK_PIPELINE_STAGE_2_NONE;
5305                             barrier.srcAccessMask         = VK_ACCESS_2_NONE;
5306                             barrier.dstStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5307                             barrier.dstAccessMask         = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5308                             barrier.oldLayout             = VK_IMAGE_LAYOUT_UNDEFINED;
5309                             barrier.newLayout             = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5310                             barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5311                             barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5312                             barrier.image                 = *dstImage.image;
5313                             barrier.subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5314 
5315                             VkDependencyInfo depInfo        = initVulkanStructure();
5316                             depInfo.imageMemoryBarrierCount = 1;
5317                             depInfo.pImageMemoryBarriers    = &barrier;
5318 
5319                             vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5320                         }
5321 
5322                         if (m_imageColorFormat == VK_FORMAT_R32_UINT)
5323                         {
5324                             VkBufferImageCopy region{};
5325                             // Use default buffer settings
5326                             region.imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1);
5327                             region.imageOffset      = makeOffset3D(0, 0, 0);
5328                             region.imageExtent = makeExtent3D(m_renderArea.extent.width, m_renderArea.extent.height, 1);
5329 
5330                             vk.cmdCopyBufferToImage(*cmdBuf, *srcBuffer.buffer, *dstImage.image,
5331                                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
5332                                                     1, // region count
5333                                                     &region);
5334                         }
5335                         else if (m_imageColorFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
5336                         {
5337                             std::vector<VkBufferImageCopy> regions(2);
5338 
5339                             regions[0].bufferOffset = 0;
5340                             regions[0].imageSubresource =
5341                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_PLANE_0_BIT, 0, 0, 1);
5342                             regions[0].imageOffset = makeOffset3D(0, 0, 0);
5343                             regions[0].imageExtent =
5344                                 makeExtent3D(m_renderArea.extent.width, m_renderArea.extent.height, 1);
5345 
5346                             regions[1].bufferOffset = m_renderArea.extent.width * m_renderArea.extent.height;
5347                             regions[1].imageSubresource =
5348                                 makeImageSubresourceLayers(VK_IMAGE_ASPECT_PLANE_1_BIT, 0, 0, 1);
5349                             regions[1].imageOffset = makeOffset3D(0, 0, 0);
5350                             regions[1].imageExtent =
5351                                 makeExtent3D(m_renderArea.extent.width / 2, m_renderArea.extent.height / 2, 1);
5352 
5353                             vk.cmdCopyBufferToImage(*cmdBuf, *srcBuffer.buffer, *dstImage.image,
5354                                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, u32(regions.size()),
5355                                                     regions.data());
5356                         }
5357                         else
5358                         {
5359                             DE_ASSERT(0);
5360                         }
5361 
5362                         {
5363                             VkImageMemoryBarrier2 barrier = initVulkanStructure();
5364                             barrier.srcStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5365                             barrier.srcAccessMask         = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5366                             barrier.dstStageMask          = dstStageMaskUp; // beginning of the shader pipeline
5367                             barrier.dstAccessMask         = VK_ACCESS_2_SHADER_READ_BIT;
5368                             barrier.oldLayout             = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
5369                             barrier.newLayout             = dstImage.layout;
5370                             barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5371                             barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5372                             barrier.image                 = *dstImage.image;
5373                             barrier.subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5374 
5375                             VkDependencyInfo depInfo        = initVulkanStructure();
5376                             depInfo.imageMemoryBarrierCount = 1;
5377                             depInfo.pImageMemoryBarriers    = &barrier;
5378 
5379                             vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5380                         }
5381                     }
5382                 }
5383                 else if (binding.descriptorType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)
5384                 {
5385                     for (uint32_t arrayIndex = 0; arrayIndex < binding.descriptorCount; ++arrayIndex)
5386                     {
5387                         ResourceHolder &resource = (**m_resources[binding.perBindingResourceIndex[arrayIndex]]);
5388 
5389                         resource.rtBlas->build(*m_deviceInterface, *m_device, *cmdBuf);
5390                         resource.rtTlas->build(*m_deviceInterface, *m_device, *cmdBuf);
5391                     }
5392                 }
5393             }
5394         }
5395 
5396         if (m_params.isCompute())
5397         {
5398             vk.cmdDispatch(*cmdBuf, 1, 1, 1);
5399 
5400             {
5401                 auto &resultBuffer = getResultBuffer();
5402 
5403                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5404                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
5405                 barrier.srcAccessMask          = VK_ACCESS_2_SHADER_WRITE_BIT;
5406                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5407                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5408                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5409                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5410                 barrier.buffer                 = *resultBuffer.buffer;
5411                 barrier.offset                 = 0;
5412                 barrier.size                   = VK_WHOLE_SIZE;
5413 
5414                 VkDependencyInfo depInfo         = initVulkanStructure();
5415                 depInfo.bufferMemoryBarrierCount = 1;
5416                 depInfo.pBufferMemoryBarriers    = &barrier;
5417 
5418                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5419             }
5420         }
5421         else if (m_params.isRayTracing())
5422         {
5423             cmdTraceRays(vk, *cmdBuf, &m_raygenShaderBindingTableRegion, &m_missShaderBindingTableRegion,
5424                          &m_hitShaderBindingTableRegion, &m_callableShaderBindingTableRegion, 1, 1, 1);
5425 
5426             {
5427                 auto &resultBuffer = getResultBuffer();
5428 
5429                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5430                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR;
5431                 barrier.srcAccessMask          = VK_ACCESS_2_SHADER_WRITE_BIT;
5432                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5433                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5434                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5435                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5436                 barrier.buffer                 = *resultBuffer.buffer;
5437                 barrier.offset                 = 0;
5438                 barrier.size                   = VK_WHOLE_SIZE;
5439 
5440                 VkDependencyInfo depInfo         = initVulkanStructure();
5441                 depInfo.bufferMemoryBarrierCount = 1;
5442                 depInfo.pBufferMemoryBarriers    = &barrier;
5443 
5444                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5445             }
5446         }
5447         else
5448         {
5449             beginRenderPass(vk, *cmdBuf, *m_renderPass, *m_framebuffer, m_renderArea, tcu::Vec4());
5450 
5451             vk.cmdDraw(*cmdBuf, 6, 1, 0, 0);
5452 
5453             endRenderPass(vk, *cmdBuf);
5454 
5455             // Copy the rendered image to a host-visible buffer.
5456 
5457             {
5458                 VkImageMemoryBarrier2 barrier = initVulkanStructure();
5459                 barrier.srcStageMask          = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
5460                 barrier.srcAccessMask         = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
5461                 barrier.dstStageMask          = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5462                 barrier.dstAccessMask         = VK_ACCESS_2_TRANSFER_READ_BIT;
5463                 barrier.oldLayout             = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5464                 barrier.newLayout             = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
5465                 barrier.srcQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5466                 barrier.dstQueueFamilyIndex   = VK_QUEUE_FAMILY_IGNORED;
5467                 barrier.image                 = *m_colorImage.image;
5468                 barrier.subresourceRange      = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
5469 
5470                 VkDependencyInfo depInfo        = initVulkanStructure();
5471                 depInfo.imageMemoryBarrierCount = 1;
5472                 depInfo.pImageMemoryBarriers    = &barrier;
5473 
5474                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5475             }
5476             {
5477                 VkBufferImageCopy region{};
5478                 // Use default buffer settings
5479                 region.imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1);
5480                 region.imageOffset      = makeOffset3D(0, 0, 0);
5481                 region.imageExtent      = m_colorImage.info.extent;
5482 
5483                 vk.cmdCopyImageToBuffer(*cmdBuf, *m_colorImage.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
5484                                         *m_colorBuffer.buffer,
5485                                         1, // region count
5486                                         &region);
5487             }
5488             {
5489                 VkBufferMemoryBarrier2 barrier = initVulkanStructure();
5490                 barrier.srcStageMask           = VK_PIPELINE_STAGE_2_TRANSFER_BIT;
5491                 barrier.srcAccessMask          = VK_ACCESS_2_TRANSFER_WRITE_BIT;
5492                 barrier.dstStageMask           = VK_PIPELINE_STAGE_2_HOST_BIT;
5493                 barrier.dstAccessMask          = VK_ACCESS_2_HOST_READ_BIT;
5494                 barrier.srcQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5495                 barrier.dstQueueFamilyIndex    = VK_QUEUE_FAMILY_IGNORED;
5496                 barrier.buffer                 = *m_colorBuffer.buffer;
5497                 barrier.offset                 = 0;
5498                 barrier.size                   = VK_WHOLE_SIZE;
5499 
5500                 VkDependencyInfo depInfo         = initVulkanStructure();
5501                 depInfo.bufferMemoryBarrierCount = 1;
5502                 depInfo.pBufferMemoryBarriers    = &barrier;
5503 
5504                 vk.cmdPipelineBarrier2(*cmdBuf, &depInfo);
5505             }
5506         }
5507 
5508         endCommandBuffer(vk, *cmdBuf);
5509         submitCommandsAndWait(vk, *m_device, m_queue, *cmdBuf);
5510     }
5511 
5512     // Verification
5513     {
5514         const tcu::UVec4 *pResultData = nullptr;
5515 
5516         if (m_params.isCompute() || m_params.isRayTracing())
5517         {
5518             auto &resultBuffer = getResultBuffer();
5519 
5520             invalidateAlloc(vk, *m_device, *resultBuffer.alloc);
5521 
5522             pResultData = static_cast<const tcu::UVec4 *>(resultBuffer.alloc->getHostPtr());
5523         }
5524         else
5525         {
5526             pResultData = static_cast<const tcu::UVec4 *>(m_colorBuffer.alloc->getHostPtr());
5527         }
5528 
5529         const auto actual = pResultData->x();
5530         uint32_t expected = 0;
5531 
5532         for (const auto &sb : m_simpleBindings)
5533         {
5534             if (!(sb.isResultBuffer || sb.isRayTracingAS))
5535             {
5536                 if (m_params.variant == TestVariant::MAX)
5537                 {
5538                     // We test enough (image, sampler) pairs to access each one at least once.
5539                     expected = deMaxu32(m_params.samplerBufferBindingCount, m_params.resourceBufferBindingCount);
5540                 }
5541                 else
5542                 {
5543                     // Uniform blocks/buffers check 4 elements per iteration.
5544                     if (sb.type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
5545                     {
5546                         expected += ConstChecksPerBuffer * 4;
5547                     }
5548                     else if (sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
5549                     {
5550                         expected += ConstChecksPerBuffer * 4 * sb.count;
5551                     }
5552                     else if ((sb.type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
5553                              (sb.type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) ||
5554                              (sb.type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER))
5555                     {
5556                         expected += ConstChecksPerBuffer * sb.count;
5557                     }
5558                     // Samplers are tested implicitly via sampled images
5559                     else if (sb.type != VK_DESCRIPTOR_TYPE_SAMPLER)
5560                     {
5561                         expected += sb.count;
5562                     }
5563                 }
5564             }
5565         }
5566 
5567         if (actual != expected)
5568         {
5569             uint32_t badSet        = 0;
5570             uint32_t badBinding    = 0;
5571             uint32_t badArrayIndex = 0;
5572 
5573             unpackBindingArgs(pResultData->y(), &badSet, &badBinding, &badArrayIndex);
5574 
5575             std::ostringstream msg;
5576             msg << "Wrong value in result buffer. Expected (" << expected << ") but got (" << actual << ").";
5577             msg << " The first wrong binding is (set = " << badSet << ", binding = " << badBinding << ")";
5578 
5579             if (m_params.variant == TestVariant::MAX)
5580             {
5581                 uint32_t badSamplerSet     = 0;
5582                 uint32_t badSamplerBinding = 0;
5583 
5584                 unpackBindingArgs(pResultData->z(), &badSamplerSet, &badSamplerBinding, nullptr);
5585 
5586                 msg << " which used a sampler (set = " << badSamplerSet << ", binding = " << badSamplerBinding << ")";
5587             }
5588             else if (badArrayIndex > 0)
5589             {
5590                 msg << " at array index " << badArrayIndex;
5591             }
5592 
5593             msg << ".";
5594 
5595             return tcu::TestStatus::fail(msg.str());
5596         }
5597     }
5598 
5599     if ((m_params.variant == TestVariant::CAPTURE_REPLAY) && (m_testIteration == 0))
5600     {
5601         // The first pass succeeded, continue to the next one where we verify replay.
5602         ++m_testIteration;
5603 
5604         return tcu::TestStatus::incomplete();
5605     }
5606 
5607     return tcu::TestStatus::pass("Pass");
5608 }
5609 
createInstance(Context & context) const5610 TestInstance *DescriptorBufferTestCase::createInstance(Context &context) const
5611 {
5612     // Currently all tests follow the same basic execution logic.
5613     return new DescriptorBufferTestInstance(context, m_params, m_simpleBindings);
5614 }
5615 
5616 // This simple tests verifies extension properties against the spec limits.
5617 //
testLimits(Context & context)5618 tcu::TestStatus testLimits(Context &context)
5619 {
5620 #define CHECK_MIN_LIMIT(_struct_, _field_, _limit_)               \
5621     if (_struct_._field_ < _limit_)                               \
5622     {                                                             \
5623         TCU_THROW(TestError, #_field_ " is less than " #_limit_); \
5624     }
5625 
5626 // Max implicitly checks nonzero too
5627 #define CHECK_MAX_LIMIT_NON_ZERO(_struct_, _field_, _limit_)         \
5628     if (_struct_._field_ == 0)                                       \
5629     {                                                                \
5630         TCU_THROW(TestError, #_field_ " is 0");                      \
5631     }                                                                \
5632     if (_struct_._field_ > _limit_)                                  \
5633     {                                                                \
5634         TCU_THROW(TestError, #_field_ " is greater than " #_limit_); \
5635     }
5636 
5637 #define CHECK_MAX_LIMIT(_struct_, _field_, _limit_)                  \
5638     if (_struct_._field_ > _limit_)                                  \
5639     {                                                                \
5640         TCU_THROW(TestError, #_field_ " is greater than " #_limit_); \
5641     }
5642 
5643     if (context.isDeviceFunctionalitySupported("VK_EXT_descriptor_buffer"))
5644     {
5645         const auto &features =
5646             *findStructure<VkPhysicalDeviceDescriptorBufferFeaturesEXT>(&context.getDeviceFeatures2());
5647         const auto &props =
5648             *findStructure<VkPhysicalDeviceDescriptorBufferPropertiesEXT>(&context.getDeviceProperties2());
5649         const bool hasRT = context.isDeviceFunctionalitySupported("VK_KHR_ray_tracing_pipeline") ||
5650                            context.isDeviceFunctionalitySupported("VK_KHR_ray_query");
5651         const size_t maxResourceDescriptorSize = std::max(
5652             props.storageImageDescriptorSize,
5653             std::max(props.sampledImageDescriptorSize,
5654                      std::max(props.robustUniformTexelBufferDescriptorSize,
5655                               std::max(props.robustStorageTexelBufferDescriptorSize,
5656                                        std::max(props.robustUniformBufferDescriptorSize,
5657                                                 std::max(props.robustStorageBufferDescriptorSize,
5658                                                          std::max(props.inputAttachmentDescriptorSize,
5659                                                                   std::max(props.accelerationStructureDescriptorSize,
5660                                                                            size_t(0u)))))))));
5661 
5662         DE_ASSERT(features.descriptorBuffer == VK_TRUE);
5663 
5664         // Must be queried directly from the physical device, the structure cached in the context has robustness disabled.
5665         VkPhysicalDeviceFeatures physDeviceFeatures{};
5666         context.getInstanceInterface().getPhysicalDeviceFeatures(context.getPhysicalDevice(), &physDeviceFeatures);
5667 
5668         if (physDeviceFeatures.robustBufferAccess)
5669         {
5670             CHECK_MAX_LIMIT(props, robustUniformTexelBufferDescriptorSize, 256);
5671             CHECK_MAX_LIMIT(props, robustStorageTexelBufferDescriptorSize, 256);
5672             CHECK_MAX_LIMIT(props, robustUniformBufferDescriptorSize, 256);
5673             CHECK_MAX_LIMIT(props, robustStorageBufferDescriptorSize, 256);
5674         }
5675 
5676         if (features.descriptorBufferCaptureReplay)
5677         {
5678             CHECK_MAX_LIMIT(props, bufferCaptureReplayDescriptorDataSize, 64);
5679             CHECK_MAX_LIMIT(props, imageCaptureReplayDescriptorDataSize, 64);
5680             CHECK_MAX_LIMIT(props, imageViewCaptureReplayDescriptorDataSize, 64);
5681             CHECK_MAX_LIMIT(props, samplerCaptureReplayDescriptorDataSize, 64);
5682 
5683             if (hasRT)
5684             {
5685                 CHECK_MAX_LIMIT(props, accelerationStructureCaptureReplayDescriptorDataSize, 64);
5686             }
5687         }
5688 
5689         if (hasRT)
5690         {
5691             CHECK_MAX_LIMIT_NON_ZERO(props, accelerationStructureDescriptorSize, 256);
5692         }
5693 
5694         CHECK_MAX_LIMIT_NON_ZERO(props, descriptorBufferOffsetAlignment, 256);
5695 
5696         CHECK_MIN_LIMIT(props, maxDescriptorBufferBindings, 3);
5697         CHECK_MIN_LIMIT(props, maxResourceDescriptorBufferBindings, 1);
5698         CHECK_MIN_LIMIT(props, maxSamplerDescriptorBufferBindings, 1);
5699         CHECK_MIN_LIMIT(props, maxEmbeddedImmutableSamplerBindings, 1);
5700         CHECK_MIN_LIMIT(props, maxEmbeddedImmutableSamplers, 2032);
5701 
5702         CHECK_MAX_LIMIT_NON_ZERO(props, samplerDescriptorSize, 256);
5703         CHECK_MAX_LIMIT_NON_ZERO(props, combinedImageSamplerDescriptorSize, 256);
5704         CHECK_MAX_LIMIT_NON_ZERO(props, sampledImageDescriptorSize, 256);
5705         CHECK_MAX_LIMIT_NON_ZERO(props, storageImageDescriptorSize, 256);
5706         CHECK_MAX_LIMIT_NON_ZERO(props, uniformTexelBufferDescriptorSize, 256);
5707         CHECK_MAX_LIMIT_NON_ZERO(props, storageTexelBufferDescriptorSize, 256);
5708         CHECK_MAX_LIMIT_NON_ZERO(props, uniformBufferDescriptorSize, 256);
5709         CHECK_MAX_LIMIT_NON_ZERO(props, storageBufferDescriptorSize, 256);
5710         CHECK_MAX_LIMIT(props, inputAttachmentDescriptorSize, 256);
5711 
5712         CHECK_MIN_LIMIT(props, maxSamplerDescriptorBufferRange, ((1u << 11) * props.samplerDescriptorSize));
5713         CHECK_MIN_LIMIT(props, maxResourceDescriptorBufferRange,
5714                         (((1u << 20) - (1u << 15)) * maxResourceDescriptorSize));
5715         CHECK_MIN_LIMIT(props, samplerDescriptorBufferAddressSpaceSize, (1u << 27));
5716         CHECK_MIN_LIMIT(props, resourceDescriptorBufferAddressSpaceSize, (1u << 27));
5717         CHECK_MIN_LIMIT(props, descriptorBufferAddressSpaceSize, (1u << 27));
5718 
5719         // The following requirement ensures that for split combined image sampler arrays:
5720         // - there's no unnecessary padding at the end, or
5721         // - there's no risk of overrun (if somehow the sum of image and sampler was greater).
5722 
5723         if ((props.combinedImageSamplerDescriptorSingleArray == VK_FALSE) &&
5724             ((props.sampledImageDescriptorSize + props.samplerDescriptorSize) !=
5725              props.combinedImageSamplerDescriptorSize))
5726         {
5727             return tcu::TestStatus::fail(
5728                 "For combinedImageSamplerDescriptorSingleArray, it is expected that the sampled image size "
5729                 "and the sampler size add up to combinedImageSamplerDescriptorSize.");
5730         }
5731     }
5732     else
5733     {
5734         TCU_THROW(NotSupportedError, "VK_EXT_descriptor_buffer is not supported");
5735     }
5736 
5737     return tcu::TestStatus::pass("Pass");
5738 
5739 #undef CHECK_MIN_LIMIT
5740 #undef CHECK_MAX_LIMIT
5741 #undef CHECK_MAX_LIMIT_NON_ZERO
5742 }
5743 
populateDescriptorBufferTests(tcu::TestCaseGroup * topGroup)5744 void populateDescriptorBufferTests(tcu::TestCaseGroup *topGroup)
5745 {
5746     tcu::TestContext &testCtx = topGroup->getTestContext();
5747     const uint32_t baseSeed   = static_cast<uint32_t>(testCtx.getCommandLine().getBaseSeed());
5748     ;
5749     std::string caseName;
5750 
5751     const VkQueueFlagBits choiceQueues[]{
5752         VK_QUEUE_GRAPHICS_BIT,
5753         VK_QUEUE_COMPUTE_BIT,
5754     };
5755 
5756     const VkShaderStageFlagBits choiceStages[]{
5757         VK_SHADER_STAGE_VERTEX_BIT,
5758         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
5759         VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
5760         VK_SHADER_STAGE_GEOMETRY_BIT,
5761         VK_SHADER_STAGE_FRAGMENT_BIT,
5762         VK_SHADER_STAGE_COMPUTE_BIT,
5763         VK_SHADER_STAGE_RAYGEN_BIT_KHR,
5764         VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
5765         VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
5766         VK_SHADER_STAGE_MISS_BIT_KHR,
5767         VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
5768         VK_SHADER_STAGE_CALLABLE_BIT_KHR,
5769     };
5770 
5771     const bool choiceStagesCommands[]{
5772         false,
5773         true,
5774     };
5775 
5776     {
5777         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "basic"));
5778 
5779         addFunctionCase(subGroup.get(), "limits", testLimits);
5780 
5781         topGroup->addChild(subGroup.release());
5782     }
5783 
5784     {
5785         //
5786         // Basic single descriptor cases -- a quick check.
5787         //
5788         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "single"));
5789         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5790 
5791         // VK_DESCRIPTOR_TYPE_SAMPLER is tested implicitly by sampled image case.
5792         // *_BUFFER_DYNAMIC are not allowed with descriptor buffers.
5793         //
5794         const VkDescriptorType choiceDescriptors[]{
5795             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
5796             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,          VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
5797             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
5798             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,         VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
5799             VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,   VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
5800         };
5801 
5802         TestParams params{};
5803         params.variant            = TestVariant::SINGLE;
5804         params.subcase            = SubCase::NONE;
5805         params.bufferBindingCount = 1;
5806         params.setsPerBuffer      = 1;
5807         params.useMaintenance5    = false;
5808 
5809         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5810             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5811                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
5812                      ++pCommands2)
5813                     for (auto pDescriptor = choiceDescriptors; pDescriptor < DE_ARRAY_END(choiceDescriptors);
5814                          ++pDescriptor)
5815                     {
5816                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5817                         {
5818                             // Compute queue can only use compute shaders.
5819                             continue;
5820                         }
5821 
5822                         if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
5823                             (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
5824                         {
5825                             // Subpass loads are only valid in fragment stage.
5826                             continue;
5827                         }
5828 
5829                         params.stage      = *pStage;
5830                         params.queue      = *pQueue;
5831                         params.descriptor = *pDescriptor;
5832                         params.commands2  = *pCommands2;
5833 
5834                         subGroup->addChild(
5835                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5836                     }
5837 
5838         params.stage           = VK_SHADER_STAGE_COMPUTE_BIT;
5839         params.queue           = VK_QUEUE_COMPUTE_BIT;
5840         params.descriptor      = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
5841         params.useMaintenance5 = true;
5842 
5843         subGroup->addChild(new DescriptorBufferTestCase(testCtx, "compute_maintenance5", params));
5844         topGroup->addChild(subGroup.release());
5845     }
5846 
5847     {
5848         //
5849         // More complex cases. Multiple sets and bindings per buffer. Immutable samplers.
5850         //
5851         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "multiple"));
5852         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5853         const VkShaderStageFlags longTestStages =
5854             VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT;
5855 
5856         const struct
5857         {
5858             uint32_t bufferBindingCount;
5859             uint32_t setsPerBuffer;
5860         } caseOptions[] = {
5861             {1, 1}, {1, 3},  {2, 4},  {3, 1}, // 3 buffer bindings is spec minimum
5862             {8, 1}, {16, 1}, {32, 1},
5863         };
5864 
5865         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5866             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5867                 for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
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 (pOptions->bufferBindingCount >= 16 && ((*pStage) & longTestStages) == 0)
5876                     {
5877                         // Allow long tests for certain stages only, skip on rest stages
5878                         continue;
5879                     }
5880 
5881                     TestParams params{};
5882                     params.variant                    = TestVariant::MULTIPLE;
5883                     params.subcase                    = SubCase::NONE;
5884                     params.stage                      = *pStage;
5885                     params.queue                      = *pQueue;
5886                     params.bufferBindingCount         = pOptions->bufferBindingCount;
5887                     params.samplerBufferBindingCount  = pOptions->bufferBindingCount;
5888                     params.resourceBufferBindingCount = pOptions->bufferBindingCount;
5889                     params.setsPerBuffer              = pOptions->setsPerBuffer;
5890                     params.descriptor =
5891                         VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; // Optional, will be tested if supported
5892                     params.useMaintenance5 = false;
5893 
5894                     subGroup->addChild(
5895                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5896 
5897                     if ((pOptions->setsPerBuffer != 1) && (pOptions->bufferBindingCount < 4))
5898                     {
5899                         // For the smaller binding counts add a subcase with immutable samplers.
5900 
5901                         params.subcase = SubCase::IMMUTABLE_SAMPLERS;
5902 
5903                         subGroup->addChild(
5904                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5905                     }
5906                 }
5907 
5908         topGroup->addChild(subGroup.release());
5909     }
5910 
5911     {
5912         //
5913         // These cases exercise buffers of single usage (samplers only and resources only) and tries to use
5914         // all available buffer bindings.
5915         //
5916         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "max"));
5917         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5918 
5919         const struct
5920         {
5921             uint32_t samplerBufferBindingCount;
5922             uint32_t resourceBufferBindingCount;
5923         } caseOptions[] = {
5924             {1, 1}, {2, 2}, {4, 4}, {8, 8}, {16, 16}, {1, 7}, {1, 15}, {1, 31}, {7, 1}, {15, 1}, {31, 1},
5925         };
5926 
5927         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5928             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5929                 for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
5930                 {
5931                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5932                     {
5933                         // Compute queue can only use compute shaders.
5934                         continue;
5935                     }
5936 
5937                     if (isAllRayTracingStages(*pStage) &&
5938                         (pOptions->samplerBufferBindingCount > 15 || pOptions->resourceBufferBindingCount > 15))
5939                     {
5940                         // Limit ray tracing stages
5941                         continue;
5942                     }
5943 
5944                     TestParams params{};
5945                     params.variant                    = TestVariant::MAX;
5946                     params.subcase                    = SubCase::NONE;
5947                     params.stage                      = *pStage;
5948                     params.queue                      = *pQueue;
5949                     params.samplerBufferBindingCount  = pOptions->samplerBufferBindingCount;
5950                     params.resourceBufferBindingCount = pOptions->resourceBufferBindingCount;
5951                     params.bufferBindingCount =
5952                         pOptions->samplerBufferBindingCount + pOptions->resourceBufferBindingCount;
5953                     params.setsPerBuffer   = 1;
5954                     params.descriptor      = VK_DESCRIPTOR_TYPE_MAX_ENUM;
5955                     params.useMaintenance5 = false;
5956 
5957                     subGroup->addChild(
5958                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
5959                 }
5960 
5961         topGroup->addChild(subGroup.release());
5962     }
5963 
5964     {
5965         //
5966         // Check embedded immutable sampler buffers/bindings.
5967         //
5968         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "embedded_imm_samplers"));
5969         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
5970 
5971         const struct
5972         {
5973             uint32_t bufferBindingCount;
5974             uint32_t samplersPerBuffer;
5975         } caseOptions[] = {
5976             {1, 1}, {1, 2}, {1, 4}, {1, 8}, {1, 16}, {2, 1}, {2, 2}, {3, 1}, {3, 3}, {8, 1}, {8, 4},
5977         };
5978 
5979         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
5980             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
5981                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
5982                      ++pCommands2)
5983                     for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
5984                     {
5985                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
5986                         {
5987                             // Compute queue can only use compute shaders.
5988                             continue;
5989                         }
5990 
5991                         TestParams params{};
5992                         params.variant                                    = TestVariant::EMBEDDED_IMMUTABLE_SAMPLERS;
5993                         params.subcase                                    = SubCase::NONE;
5994                         params.stage                                      = *pStage;
5995                         params.queue                                      = *pQueue;
5996                         params.bufferBindingCount                         = pOptions->bufferBindingCount + 1;
5997                         params.samplerBufferBindingCount                  = pOptions->bufferBindingCount;
5998                         params.resourceBufferBindingCount                 = 1;
5999                         params.setsPerBuffer                              = 1;
6000                         params.embeddedImmutableSamplerBufferBindingCount = pOptions->bufferBindingCount;
6001                         params.embeddedImmutableSamplersPerBuffer         = pOptions->samplersPerBuffer;
6002                         params.descriptor                                 = VK_DESCRIPTOR_TYPE_MAX_ENUM;
6003                         params.useMaintenance5                            = false;
6004                         params.commands2                                  = *pCommands2;
6005 
6006                         subGroup->addChild(
6007                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6008                     }
6009 
6010         topGroup->addChild(subGroup.release());
6011     }
6012 
6013     {
6014         //
6015         // Check push descriptors and push descriptors with template updates
6016         //
6017         MovePtr<tcu::TestCaseGroup> subGroupPush(new tcu::TestCaseGroup(testCtx, "push_descriptor"));
6018         MovePtr<tcu::TestCaseGroup> subGroupPushTemplate(new tcu::TestCaseGroup(testCtx, "push_template"));
6019         const uint32_t subGroupPushHash         = baseSeed ^ deStringHash(subGroupPush->getName());
6020         const uint32_t subGroupPushTemplateHash = baseSeed ^ deStringHash(subGroupPushTemplate->getName());
6021 
6022         const struct
6023         {
6024             uint32_t pushDescriptorSetIndex;
6025             uint32_t bufferBindingCount;
6026 
6027             // The total number of descriptor sets will be bufferBindingCount + 1, where the additional set is used for push descriptors.
6028 
6029         } caseOptions[] = {
6030             {0, 0}, // Only push descriptors
6031             {0, 1}, {0, 3}, {1, 1}, {0, 2},
6032             {1, 2}, {2, 2}, // index = 2 means 3 sets, where the first two are used with descriptor buffer and the last with push descriptors
6033             {3, 3},
6034         };
6035 
6036         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6037             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6038                 for (auto pCommands2 = choiceStagesCommands; pCommands2 < DE_ARRAY_END(choiceStagesCommands);
6039                      ++pCommands2)
6040                     for (auto pOptions = caseOptions; pOptions < DE_ARRAY_END(caseOptions); ++pOptions)
6041                     {
6042                         if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6043                         {
6044                             // Compute queue can only use compute shaders.
6045                             continue;
6046                         }
6047 
6048                         TestParams params{};
6049                         params.variant                    = TestVariant::PUSH_DESCRIPTOR;
6050                         params.subcase                    = SubCase::NONE;
6051                         params.stage                      = *pStage;
6052                         params.queue                      = *pQueue;
6053                         params.bufferBindingCount         = pOptions->bufferBindingCount;
6054                         params.samplerBufferBindingCount  = pOptions->bufferBindingCount;
6055                         params.resourceBufferBindingCount = pOptions->bufferBindingCount;
6056                         params.setsPerBuffer              = 1;
6057                         params.pushDescriptorSetIndex     = pOptions->pushDescriptorSetIndex;
6058                         params.descriptor =
6059                             VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; // Optional, will be tested if supported
6060                         params.useMaintenance5 = false;
6061                         params.commands2       = *pCommands2;
6062 
6063                         subGroupPush->addChild(new DescriptorBufferTestCase(
6064                             testCtx, getCaseNameUpdateHash(params, subGroupPushHash), params));
6065 
6066                         if (pOptions->bufferBindingCount < 2)
6067                         {
6068                             TestParams paramsSingleBuffer = params;
6069 
6070                             paramsSingleBuffer.subcase = SubCase::SINGLE_BUFFER;
6071 
6072                             subGroupPush->addChild(new DescriptorBufferTestCase(
6073                                 testCtx, getCaseNameUpdateHash(paramsSingleBuffer, subGroupPushHash),
6074                                 paramsSingleBuffer));
6075                         }
6076 
6077                         params.variant = TestVariant::PUSH_TEMPLATE;
6078 
6079                         subGroupPushTemplate->addChild(new DescriptorBufferTestCase(
6080                             testCtx, getCaseNameUpdateHash(params, subGroupPushTemplateHash), params));
6081                     }
6082 
6083         topGroup->addChild(subGroupPush.release());
6084         topGroup->addChild(subGroupPushTemplate.release());
6085     }
6086 
6087     {
6088         //
6089         // Robustness tests
6090         //
6091         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "robust"));
6092         MovePtr<tcu::TestCaseGroup> subGroupBuffer(new tcu::TestCaseGroup(testCtx, "buffer_access"));
6093         MovePtr<tcu::TestCaseGroup> subGroupNullDescriptor(new tcu::TestCaseGroup(testCtx, "null_descriptor"));
6094         const uint32_t subGroupBufferHash         = baseSeed ^ deStringHash(subGroupBuffer->getName());
6095         const uint32_t subGroupNullDescriptorHash = baseSeed ^ deStringHash(subGroupNullDescriptor->getName());
6096 
6097         // Robust buffer access:
6098         // This test will fill the buffers with zeros and always expect to read zero values back (in and out of bounds).
6099 
6100         // Null descriptor cases:
6101         // For each test, one of these descriptors will have its buffer/imageView/etc. set to null handle.
6102         // Reads done through a null descriptor are expected to return zeros.
6103         //
6104         const VkDescriptorType choiceNullDescriptors[]{
6105             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
6106             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,          VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
6107             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,   VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
6108             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,         VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
6109         };
6110 
6111         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6112             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6113             {
6114                 if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6115                 {
6116                     // Compute queue can only use compute shaders.
6117                     continue;
6118                 }
6119 
6120                 TestParams params{};
6121                 params.variant            = TestVariant::ROBUST_BUFFER_ACCESS;
6122                 params.stage              = *pStage;
6123                 params.queue              = *pQueue;
6124                 params.bufferBindingCount = 1;
6125                 params.setsPerBuffer      = 1;
6126                 params.useMaintenance5    = false;
6127 
6128                 subGroupBuffer->addChild(
6129                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupBufferHash), params));
6130 
6131                 for (auto pDescriptor = choiceNullDescriptors; pDescriptor < DE_ARRAY_END(choiceNullDescriptors);
6132                      ++pDescriptor)
6133                 {
6134                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
6135                         (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
6136                     {
6137                         // Subpass loads are only valid in fragment stage.
6138                         continue;
6139                     }
6140 
6141                     params.variant    = TestVariant::ROBUST_NULL_DESCRIPTOR;
6142                     params.descriptor = *pDescriptor;
6143 
6144                     subGroupNullDescriptor->addChild(new DescriptorBufferTestCase(
6145                         testCtx, getCaseNameUpdateHash(params, subGroupNullDescriptorHash), params));
6146                 }
6147             }
6148 
6149         subGroup->addChild(subGroupBuffer.release());
6150         subGroup->addChild(subGroupNullDescriptor.release());
6151         topGroup->addChild(subGroup.release());
6152     }
6153 
6154     {
6155         //
6156         // Capture and replay
6157         //
6158         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "capture_replay"));
6159         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6160 
6161         const VkDescriptorType choiceDescriptors[]{
6162             VK_DESCRIPTOR_TYPE_SAMPLER,
6163             VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // both sampler and image are captured
6164             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
6165             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6166             VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
6167             VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6168             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
6169             VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
6170             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
6171             VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
6172         };
6173 
6174         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6175             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6176                 for (auto pDescriptor = choiceDescriptors; pDescriptor < DE_ARRAY_END(choiceDescriptors); ++pDescriptor)
6177                 {
6178                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6179                     {
6180                         // Compute queue can only use compute shaders.
6181                         continue;
6182                     }
6183 
6184                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) &&
6185                         (*pStage != VK_SHADER_STAGE_FRAGMENT_BIT))
6186                     {
6187                         // Subpass loads are only valid in fragment stage.
6188                         continue;
6189                     }
6190 
6191                     TestParams params{};
6192                     params.variant            = TestVariant::CAPTURE_REPLAY;
6193                     params.subcase            = SubCase::NONE;
6194                     params.stage              = *pStage;
6195                     params.queue              = *pQueue;
6196                     params.descriptor         = *pDescriptor;
6197                     params.bufferBindingCount = 1;
6198                     params.setsPerBuffer      = 1;
6199                     params.useMaintenance5    = false;
6200 
6201                     subGroup->addChild(
6202                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6203 
6204                     if ((*pDescriptor == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
6205                         (*pDescriptor == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
6206                         (*pDescriptor == VK_DESCRIPTOR_TYPE_SAMPLER))
6207                     {
6208                         params.subcase = SubCase::CAPTURE_REPLAY_CUSTOM_BORDER_COLOR;
6209 
6210                         subGroup->addChild(
6211                             new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6212                     }
6213                 }
6214 
6215         topGroup->addChild(subGroup.release());
6216     }
6217 
6218     {
6219         //
6220         // VK_EXT_mutable_descriptor_type tests
6221         //
6222         // Similar to multiple test case, but with mutable descriptor type instead.
6223         // Rather than using mutable type for everything, there are a few subcases that determine which descriptor
6224         // types can be replaced with the mutable type.
6225         //
6226         MovePtr<tcu::TestCaseGroup> subGroup(
6227             new tcu::TestCaseGroup(testCtx, "mutable_descriptor", "Mutable descriptor type tests"));
6228         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6229 
6230         const DescriptorMask choiceDescriptorMasks[]{
6231             // Single
6232             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER}),
6233             makeDescriptorMask({VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6234             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE}),
6235             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6236             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER}),
6237             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER}),
6238             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER}),
6239             makeDescriptorMask({VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6240             makeDescriptorMask({VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6241 
6242             // Multiple - images/samplers
6243             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6244             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}),
6245             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6246             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6247             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6248                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE}),
6249             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6250                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6251                                 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}),
6252 
6253             // Multiple - buffers
6254             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER}),
6255             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6256             makeDescriptorMask({VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6257                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6258 
6259             // Everything
6260             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6261                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6262                                 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6263                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER}),
6264             makeDescriptorMask({VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
6265                                 VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
6266                                 VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
6267                                 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
6268                                 VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT}), // with input attachment
6269         };
6270 
6271         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6272             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6273                 for (auto pMask = choiceDescriptorMasks; pMask < DE_ARRAY_END(choiceDescriptorMasks); ++pMask)
6274                 {
6275                     if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6276                     {
6277                         // Compute queue can only use compute shaders.
6278                         continue;
6279                     }
6280 
6281                     if ((*pStage != VK_SHADER_STAGE_FRAGMENT_BIT) &&
6282                         (maskCheck(*pMask, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)))
6283                     {
6284                         // Subpass loads are only valid in fragment stage.
6285                         continue;
6286                     }
6287 
6288                     TestParams params{};
6289                     params.variant                = TestVariant::MUTABLE_DESCRIPTOR_TYPE;
6290                     params.stage                  = *pStage;
6291                     params.queue                  = *pQueue;
6292                     params.bufferBindingCount     = 1;
6293                     params.setsPerBuffer          = 1;
6294                     params.mutableDescriptorTypes = *pMask;
6295 
6296                     subGroup->addChild(
6297                         new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6298                 }
6299 
6300         topGroup->addChild(subGroup.release());
6301     }
6302 
6303     {
6304         //
6305         // ycbcr sampler conversion interaction
6306         //
6307         MovePtr<tcu::TestCaseGroup> subGroup(new tcu::TestCaseGroup(testCtx, "ycbcr_sampler", "ycbcr sampler tests"));
6308         const uint32_t subGroupHash = baseSeed ^ deStringHash(subGroup->getName());
6309 
6310         for (auto pQueue = choiceQueues; pQueue < DE_ARRAY_END(choiceQueues); ++pQueue)
6311             for (auto pStage = choiceStages; pStage < DE_ARRAY_END(choiceStages); ++pStage)
6312             {
6313                 if ((*pQueue == VK_QUEUE_COMPUTE_BIT) && (*pStage != VK_SHADER_STAGE_COMPUTE_BIT))
6314                 {
6315                     // Compute queue can only use compute shaders.
6316                     continue;
6317                 }
6318 
6319                 TestParams params{};
6320                 params.variant            = TestVariant::YCBCR_SAMPLER;
6321                 params.subcase            = SubCase::NONE;
6322                 params.stage              = *pStage;
6323                 params.queue              = *pQueue;
6324                 params.descriptor         = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
6325                 params.bufferBindingCount = 1;
6326                 params.setsPerBuffer      = 1;
6327 
6328                 subGroup->addChild(
6329                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6330 
6331                 params.subcase = SubCase::YCBCR_SAMPLER_ARRAY;
6332 
6333                 subGroup->addChild(
6334                     new DescriptorBufferTestCase(testCtx, getCaseNameUpdateHash(params, subGroupHash), params));
6335             }
6336 
6337         topGroup->addChild(subGroup.release());
6338     }
6339 }
6340 
6341 } // namespace
6342 
createDescriptorBufferTests(tcu::TestContext & testCtx)6343 tcu::TestCaseGroup *createDescriptorBufferTests(tcu::TestContext &testCtx)
6344 {
6345     return createTestGroup(testCtx, "descriptor_buffer", populateDescriptorBufferTests);
6346 }
6347 
6348 } // namespace BindingModel
6349 } // namespace vkt
6350