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