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