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