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