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 ¶ms, 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 ¶ms, 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 ¶ms, 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 ¶ms)
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 ¶ms,
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 ¶ms,
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 ©);
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 ®ion);
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 ®ion);
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