• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 Valve Corporation.
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
22  * \brief Tests for VK_VALVE_mutable_descriptor_type.
23  *//*--------------------------------------------------------------------*/
24 #include "vktBindingValveMutableTests.hpp"
25 #include "vktTestCase.hpp"
26 
27 #include "vkDefs.hpp"
28 #include "vkRefUtil.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkImageWithMemory.hpp"
31 #include "vkBufferWithMemory.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkRayTracingUtil.hpp"
38 
39 #include "deUniquePtr.hpp"
40 #include "deSTLUtil.hpp"
41 #include "deStringUtil.hpp"
42 
43 #include <vector>
44 #include <algorithm>
45 #include <iterator>
46 #include <set>
47 #include <sstream>
48 #include <limits>
49 
50 namespace vkt
51 {
52 namespace BindingModel
53 {
54 
55 namespace
56 {
57 
58 using namespace vk;
59 
getDescriptorNumericValue(deUint32 iteration,deUint32 bindingIdx,deUint32 descriptorIdx=0u)60 deUint32 getDescriptorNumericValue (deUint32 iteration, deUint32 bindingIdx, deUint32 descriptorIdx = 0u)
61 {
62 	// When assigning numeric values for the descriptor contents, each descriptor will get 0x5aIIBBDD. II is an octed containing the
63 	// iteration index. BB is an octet containing the binding index and DD is the descriptor index inside that binding.
64 	constexpr deUint32 kNumericValueBase = 0x5a000000u;
65 
66 	return (kNumericValueBase | ((iteration & 0xFFu) << 16) | ((bindingIdx & 0xFFu) << 8) | (descriptorIdx & 0xFFu));
67 }
68 
getAccelerationStructureOffsetX(deUint32 descriptorNumericValue)69 deUint16 getAccelerationStructureOffsetX (deUint32 descriptorNumericValue)
70 {
71 	// Keep the lowest 16 bits (binding and descriptor idx) as the offset.
72 	return static_cast<deUint16>(descriptorNumericValue);
73 }
74 
75 // Value that will be stored in the output buffer to signal success reading values.
getExpectedOutputBufferValue()76 deUint32 getExpectedOutputBufferValue ()
77 {
78 	return 2u;
79 }
80 
81 // This value will be stored in an image to be sampled when checking descriptors containing samplers alone.
getExternalSampledImageValue()82 deUint32 getExternalSampledImageValue ()
83 {
84 	return 0x41322314u;
85 }
86 
87 // Value that will be ORed with the descriptor value before writing.
getStoredValueMask()88 deUint32 getStoredValueMask ()
89 {
90 	return 0xFF000000u;
91 }
92 
getDescriptorImageFormat()93 VkFormat getDescriptorImageFormat ()
94 {
95 	return VK_FORMAT_R32_UINT;
96 }
97 
getDefaultExtent()98 VkExtent3D getDefaultExtent ()
99 {
100 	return makeExtent3D(1u, 1u, 1u);
101 }
102 
103 // Convert value to hexadecimal.
toHex(deUint32 val)104 std::string toHex (deUint32 val)
105 {
106 	std::ostringstream s;
107 	s << "0x" << std::hex << val << "u";
108 	return s.str();
109 }
110 
111 // Returns the list of descriptor types that cannot be part of a mutable descriptor.
getForbiddenMutableTypes()112 std::vector<VkDescriptorType> getForbiddenMutableTypes ()
113 {
114 	return std::vector<VkDescriptorType>
115 		{
116 			VK_DESCRIPTOR_TYPE_MUTABLE_VALVE,
117 			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
118 			VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
119 			VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT,
120 		};
121 }
122 
123 // Returns the list of descriptor types that are mandatory for the extension.
getMandatoryMutableTypes()124 std::vector<VkDescriptorType> getMandatoryMutableTypes ()
125 {
126 	return std::vector<VkDescriptorType>
127 		{
128 			VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
129 			VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
130 			VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
131 			VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
132 			VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
133 			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
134 		};
135 }
136 
137 // This helps quickly transform a vector of descriptor types into a bitmask, which makes it easier to check some conditions.
138 enum DescriptorTypeFlagBits
139 {
140 	DTFB_SAMPLER                    = (1 << 0),
141 	DTFB_COMBINED_IMAGE_SAMPLER     = (1 << 1),
142 	DTFB_SAMPLED_IMAGE              = (1 << 2),
143 	DTFB_STORAGE_IMAGE              = (1 << 3),
144 	DTFB_UNIFORM_TEXEL_BUFFER       = (1 << 4),
145 	DTFB_STORAGE_TEXEL_BUFFER       = (1 << 5),
146 	DTFB_UNIFORM_BUFFER             = (1 << 6),
147 	DTFB_STORAGE_BUFFER             = (1 << 7),
148 	DTFB_UNIFORM_BUFFER_DYNAMIC     = (1 << 8),
149 	DTFB_STORAGE_BUFFER_DYNAMIC     = (1 << 9),
150 	DTFB_INPUT_ATTACHMENT           = (1 << 10),
151 	DTFB_INLINE_UNIFORM_BLOCK_EXT   = (1 << 11),
152 	DTFB_ACCELERATION_STRUCTURE_KHR = (1 << 12),
153 	DTFB_ACCELERATION_STRUCTURE_NV  = (1 << 13),
154 	DTFB_MUTABLE_VALVE              = (1 << 14),
155 };
156 
157 using DescriptorTypeFlags = deUint32;
158 
159 // Convert type to its corresponding flag bit.
toDescriptorTypeFlagBit(VkDescriptorType descriptorType)160 DescriptorTypeFlagBits toDescriptorTypeFlagBit (VkDescriptorType descriptorType)
161 {
162 	switch (descriptorType)
163 	{
164 	case VK_DESCRIPTOR_TYPE_SAMPLER:                        return DTFB_SAMPLER;
165 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:         return DTFB_COMBINED_IMAGE_SAMPLER;
166 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:                  return DTFB_SAMPLED_IMAGE;
167 	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:                  return DTFB_STORAGE_IMAGE;
168 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:           return DTFB_UNIFORM_TEXEL_BUFFER;
169 	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:           return DTFB_STORAGE_TEXEL_BUFFER;
170 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:                 return DTFB_UNIFORM_BUFFER;
171 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:                 return DTFB_STORAGE_BUFFER;
172 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:         return DTFB_UNIFORM_BUFFER_DYNAMIC;
173 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:         return DTFB_STORAGE_BUFFER_DYNAMIC;
174 	case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:               return DTFB_INPUT_ATTACHMENT;
175 	case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:       return DTFB_INLINE_UNIFORM_BLOCK_EXT;
176 	case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:     return DTFB_ACCELERATION_STRUCTURE_KHR;
177 	case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV:      return DTFB_ACCELERATION_STRUCTURE_NV;
178 	case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE:                  return DTFB_MUTABLE_VALVE;
179 	default: break;
180 	}
181 
182 	// Unreachable.
183 	DE_ASSERT(false);
184 	return DTFB_SAMPLER;
185 }
186 
187 // Convert vector of descriptor types to a bitfield.
toDescriptorTypeFlags(const std::vector<VkDescriptorType> & types)188 DescriptorTypeFlags toDescriptorTypeFlags (const std::vector<VkDescriptorType>& types)
189 {
190 	DescriptorTypeFlags result = 0u;
191 	for (const auto& t : types)
192 		result |= toDescriptorTypeFlagBit(t);
193 	return result;
194 }
195 
196 // Convert bitfield to vector of descriptor types.
toDescriptorTypeVector(DescriptorTypeFlags bitfield)197 std::vector<VkDescriptorType> toDescriptorTypeVector (DescriptorTypeFlags bitfield)
198 {
199 	std::vector<VkDescriptorType> result;
200 
201 	if (bitfield & DTFB_SAMPLER)                     result.push_back(VK_DESCRIPTOR_TYPE_SAMPLER);
202 	if (bitfield & DTFB_COMBINED_IMAGE_SAMPLER)      result.push_back(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
203 	if (bitfield & DTFB_SAMPLED_IMAGE)               result.push_back(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
204 	if (bitfield & DTFB_STORAGE_IMAGE)               result.push_back(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
205 	if (bitfield & DTFB_UNIFORM_TEXEL_BUFFER)        result.push_back(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
206 	if (bitfield & DTFB_STORAGE_TEXEL_BUFFER)        result.push_back(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
207 	if (bitfield & DTFB_UNIFORM_BUFFER)              result.push_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
208 	if (bitfield & DTFB_STORAGE_BUFFER)              result.push_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
209 	if (bitfield & DTFB_UNIFORM_BUFFER_DYNAMIC)      result.push_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
210 	if (bitfield & DTFB_STORAGE_BUFFER_DYNAMIC)      result.push_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
211 	if (bitfield & DTFB_INPUT_ATTACHMENT)            result.push_back(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
212 	if (bitfield & DTFB_INLINE_UNIFORM_BLOCK_EXT)    result.push_back(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
213 	if (bitfield & DTFB_ACCELERATION_STRUCTURE_KHR)  result.push_back(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
214 	if (bitfield & DTFB_ACCELERATION_STRUCTURE_NV)   result.push_back(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
215 	if (bitfield & DTFB_MUTABLE_VALVE)               result.push_back(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE);
216 
217 	return result;
218 }
219 
220 // How to create the source set when copying descriptors from another set.
221 // * MUTABLE means to transform bindings into mutable bindings.
222 // * NONMUTABLE means to transform bindings into non-mutable bindings.
223 enum class SourceSetStrategy
224 {
225 	MUTABLE = 0,
226 	NONMUTABLE,
227 	NO_SOURCE,
228 };
229 
230 enum class PoolMutableStrategy
231 {
232 	KEEP_TYPES = 0,
233 	EXPAND_TYPES,
234 	NO_TYPES,
235 };
236 
237 // Type of information that's present in VkWriteDescriptorSet.
238 enum class WriteType
239 {
240 	IMAGE_INFO = 0,
241 	BUFFER_INFO,
242 	BUFFER_VIEW,
243 	ACCELERATION_STRUCTURE_INFO,
244 };
245 
246 struct WriteInfo
247 {
248 	WriteType writeType;
249 	union
250 	{
251 		VkDescriptorImageInfo                           imageInfo;
252 		VkDescriptorBufferInfo                          bufferInfo;
253 		VkBufferView                                    bufferView;
254 		VkWriteDescriptorSetAccelerationStructureKHR    asInfo;
255 	};
256 
WriteInfovkt::BindingModel::__anon511c6de30111::WriteInfo257 	explicit WriteInfo (const VkDescriptorImageInfo& info_)
258 		: writeType(WriteType::IMAGE_INFO)
259 		, imageInfo(info_)
260 	{}
261 
WriteInfovkt::BindingModel::__anon511c6de30111::WriteInfo262 	explicit WriteInfo (const VkDescriptorBufferInfo& info_)
263 		: writeType(WriteType::BUFFER_INFO)
264 		, bufferInfo(info_)
265 	{}
266 
WriteInfovkt::BindingModel::__anon511c6de30111::WriteInfo267 	explicit WriteInfo (VkBufferView view_)
268 		: writeType(WriteType::BUFFER_VIEW)
269 		, bufferView(view_)
270 	{}
271 
WriteInfovkt::BindingModel::__anon511c6de30111::WriteInfo272 	explicit WriteInfo (const VkWriteDescriptorSetAccelerationStructureKHR& asInfo_)
273 		: writeType(WriteType::ACCELERATION_STRUCTURE_INFO)
274 		, asInfo(asInfo_)
275 	{}
276 };
277 
278 // Resource backing up a single binding.
279 enum class ResourceType
280 {
281 	SAMPLER = 0,
282 	IMAGE,
283 	COMBINED_IMAGE_SAMPLER,
284 	BUFFER,
285 	BUFFER_VIEW,
286 	ACCELERATION_STRUCTURE,
287 };
288 
289 // Type of resource backing up a particular descriptor type.
toResourceType(VkDescriptorType descriptorType)290 ResourceType toResourceType (VkDescriptorType descriptorType)
291 {
292 	ResourceType resourceType = ResourceType::SAMPLER;
293 	switch (descriptorType)
294 	{
295 	case VK_DESCRIPTOR_TYPE_SAMPLER:
296 		resourceType = ResourceType::SAMPLER;
297 		break;
298 
299 	case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
300 		resourceType = ResourceType::COMBINED_IMAGE_SAMPLER;
301 		break;
302 
303 	case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
304 	case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
305 	case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
306 		resourceType = ResourceType::IMAGE;
307 		break;
308 
309 	case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
310 	case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
311 		resourceType = ResourceType::BUFFER_VIEW;
312 		break;
313 
314 	case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
315 	case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
316 		resourceType = ResourceType::BUFFER;
317 		break;
318 
319 	case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
320 		resourceType = ResourceType::ACCELERATION_STRUCTURE;
321 		break;
322 
323 	default:
324 		DE_ASSERT(false);
325 		break;
326 	}
327 
328 	return resourceType;
329 }
330 
isShaderWritable(VkDescriptorType descriptorType)331 bool isShaderWritable (VkDescriptorType descriptorType)
332 {
333 	return (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ||
334 	        descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
335 }
336 
makeDefaultSampler(const DeviceInterface & vkd,VkDevice device)337 Move<VkSampler> makeDefaultSampler (const DeviceInterface& vkd, VkDevice device)
338 {
339 	const VkSamplerCreateInfo samplerCreateInfo = {
340 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,  //  VkStructureType			sType;
341 		nullptr,                                //  const void*				pNext;
342 		0u,                                     //  VkSamplerCreateFlags	flags;
343 		VK_FILTER_NEAREST,                      //  VkFilter				magFilter;
344 		VK_FILTER_NEAREST,                      //  VkFilter				minFilter;
345 		VK_SAMPLER_MIPMAP_MODE_NEAREST,         //  VkSamplerMipmapMode		mipmapMode;
346 		VK_SAMPLER_ADDRESS_MODE_REPEAT,         //  VkSamplerAddressMode	addressModeU;
347 		VK_SAMPLER_ADDRESS_MODE_REPEAT,         //  VkSamplerAddressMode	addressModeV;
348 		VK_SAMPLER_ADDRESS_MODE_REPEAT,         //  VkSamplerAddressMode	addressModeW;
349 		0.f,                                    //  float					mipLodBias;
350 		VK_FALSE,                               //  VkBool32				anisotropyEnable;
351 		1.f,                                    //  float					maxAnisotropy;
352 		VK_FALSE,                               //  VkBool32				compareEnable;
353 		VK_COMPARE_OP_ALWAYS,                   //  VkCompareOp				compareOp;
354 		0.f,                                    //  float					minLod;
355 		0.f,                                    //  float					maxLod;
356 		VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,  //  VkBorderColor			borderColor;
357 		VK_FALSE,                               //  VkBool32				unnormalizedCoordinates;
358 	};
359 
360 	return createSampler(vkd, device, &samplerCreateInfo);
361 }
362 
makeDefaultImage(const DeviceInterface & vkd,VkDevice device,Allocator & alloc)363 de::MovePtr<ImageWithMemory> makeDefaultImage (const DeviceInterface& vkd, VkDevice device, Allocator& alloc)
364 {
365 	const auto              extent     = makeExtent3D(1u, 1u, 1u);
366 	const VkImageUsageFlags usageFlags = (
367 		VK_IMAGE_USAGE_SAMPLED_BIT
368 		| VK_IMAGE_USAGE_STORAGE_BIT
369 		| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
370 		| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
371 		| VK_IMAGE_USAGE_TRANSFER_SRC_BIT
372 		| VK_IMAGE_USAGE_TRANSFER_DST_BIT);
373 
374 	const VkImageCreateInfo imageCreateInfo = {
375 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,    //  VkStructureType			sType;
376 		nullptr,                                //  const void*				pNext;
377 		0u,                                     //  VkImageCreateFlags		flags;
378 		VK_IMAGE_TYPE_2D,                       //  VkImageType				imageType;
379 		getDescriptorImageFormat(),             //  VkFormat				format;
380 		extent,                                 //  VkExtent3D				extent;
381 		1u,                                     //  deUint32				mipLevels;
382 		1u,                                     //  deUint32				arrayLayers;
383 		VK_SAMPLE_COUNT_1_BIT,                  //  VkSampleCountFlagBits	samples;
384 		VK_IMAGE_TILING_OPTIMAL,                //  VkImageTiling			tiling;
385 		usageFlags,                             //  VkImageUsageFlags		usage;
386 		VK_SHARING_MODE_EXCLUSIVE,              //  VkSharingMode			sharingMode;
387 		0u,                                     //  deUint32				queueFamilyIndexCount;
388 		nullptr,                                //  const deUint32*			pQueueFamilyIndices;
389 		VK_IMAGE_LAYOUT_UNDEFINED,              //  VkImageLayout			initialLayout;
390 	};
391 	return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any));
392 }
393 
makeDefaultImageView(const DeviceInterface & vkd,VkDevice device,VkImage image)394 Move<VkImageView> makeDefaultImageView (const DeviceInterface& vkd, VkDevice device, VkImage image)
395 {
396 	const auto subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
397 	return makeImageView(vkd, device, image, VK_IMAGE_VIEW_TYPE_2D, getDescriptorImageFormat(), subresourceRange);
398 }
399 
makeDefaultBuffer(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,deUint32 numElements=1u)400 de::MovePtr<BufferWithMemory> makeDefaultBuffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 numElements = 1u)
401 {
402 	const VkBufferUsageFlags bufferUsage = (
403 		VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
404 		| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
405 		| VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT
406 		| VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
407 		| VK_BUFFER_USAGE_TRANSFER_SRC_BIT
408 		| VK_BUFFER_USAGE_TRANSFER_DST_BIT);
409 
410 	const auto bufferSize = static_cast<VkDeviceSize>(sizeof(deUint32) * static_cast<size_t>(numElements));
411 
412 	const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, bufferUsage);
413 
414 	return de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
415 }
416 
makeDefaultBufferView(const DeviceInterface & vkd,VkDevice device,VkBuffer buffer)417 Move<VkBufferView> makeDefaultBufferView (const DeviceInterface& vkd, VkDevice device, VkBuffer buffer)
418 {
419 	const auto bufferOffset = static_cast<VkDeviceSize>(0);
420 	const auto bufferSize   = static_cast<VkDeviceSize>(sizeof(deUint32));
421 
422 	return makeBufferView(vkd, device, buffer, getDescriptorImageFormat(), bufferOffset, bufferSize);
423 }
424 
425 struct AccelerationStructureData
426 {
427 	using TLASPtr = de::MovePtr<TopLevelAccelerationStructure>;
428 	using BLASPtr = de::MovePtr<BottomLevelAccelerationStructure>;
429 
430 	TLASPtr tlas;
431 	BLASPtr blas;
432 
swapvkt::BindingModel::__anon511c6de30111::AccelerationStructureData433 	void swap (AccelerationStructureData& other)
434 	{
435 		auto myTlasPtr = tlas.release();
436 		auto myBlasPtr = blas.release();
437 
438 		auto otherTlasPtr = other.tlas.release();
439 		auto otherBlasPtr = other.blas.release();
440 
441 		tlas = TLASPtr(otherTlasPtr);
442 		blas = BLASPtr(otherBlasPtr);
443 
444 		other.tlas = TLASPtr(myTlasPtr);
445 		other.blas = BLASPtr(myBlasPtr);
446 	}
447 
AccelerationStructureDatavkt::BindingModel::__anon511c6de30111::AccelerationStructureData448 	AccelerationStructureData () : tlas() , blas() {}
449 
AccelerationStructureDatavkt::BindingModel::__anon511c6de30111::AccelerationStructureData450 	AccelerationStructureData (AccelerationStructureData&& other)
451 		: AccelerationStructureData()
452 	{
453 		swap(other);
454 	}
455 
operator =vkt::BindingModel::__anon511c6de30111::AccelerationStructureData456 	AccelerationStructureData& operator= (AccelerationStructureData&& other)
457 	{
458 		swap(other);
459 		return *this;
460 	}
461 };
462 
makeDefaultAccelerationStructure(const DeviceInterface & vkd,VkDevice device,VkCommandBuffer cmdBuffer,Allocator & alloc,bool triangles,deUint16 offsetX)463 AccelerationStructureData makeDefaultAccelerationStructure (const DeviceInterface& vkd, VkDevice device, VkCommandBuffer cmdBuffer, Allocator& alloc, bool triangles, deUint16 offsetX)
464 {
465 	AccelerationStructureData data;
466 
467 	// Triangle around (offsetX, 0) with depth 5.0.
468 	const float middleX = static_cast<float>(offsetX);
469 	const float leftX   = middleX - 0.5f;
470 	const float rightX  = middleX + 0.5f;
471 	const float topY    = 0.5f;
472 	const float bottomY = -0.5f;
473 	const float depth   = 5.0f;
474 
475 	std::vector<tcu::Vec3> vertices;
476 
477 	if (triangles)
478 	{
479 		vertices.reserve(3u);
480 		vertices.emplace_back(middleX, topY, depth);
481 		vertices.emplace_back(rightX, bottomY, depth);
482 		vertices.emplace_back(leftX, bottomY, depth);
483 	}
484 	else
485 	{
486 		vertices.reserve(2u);
487 		vertices.emplace_back(leftX, bottomY, depth);
488 		vertices.emplace_back(rightX, topY, depth);
489 	}
490 
491 	data.tlas = makeTopLevelAccelerationStructure();
492 	data.blas = makeBottomLevelAccelerationStructure();
493 
494 	VkGeometryInstanceFlagsKHR instanceFlags = 0u;
495 	if (triangles)
496 		instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
497 
498 	data.blas->addGeometry(vertices, triangles, VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR);
499 	data.blas->createAndBuild(vkd, device, cmdBuffer, alloc);
500 
501 	de::SharedPtr<BottomLevelAccelerationStructure> blasSharedPtr (data.blas.release());
502 	data.tlas->setInstanceCount(1u);
503 	data.tlas->addInstance(blasSharedPtr, identityMatrix3x4, 0u, 0xFFu, 0u, instanceFlags);
504 	data.tlas->createAndBuild(vkd, device, cmdBuffer, alloc);
505 
506 	return data;
507 }
508 
509 const auto kShaderAccess = (VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
510 
511 struct Resource
512 {
513 	VkDescriptorType              descriptorType;
514 	ResourceType                  resourceType;
515 	Move<VkSampler>               sampler;
516 	de::MovePtr<ImageWithMemory>  imageWithMemory;
517 	Move<VkImageView>             imageView;
518 	de::MovePtr<BufferWithMemory> bufferWithMemory;
519 	Move<VkBufferView>            bufferView;
520 	AccelerationStructureData     asData;
521 	deUint32                      initialValue;
522 
Resourcevkt::BindingModel::__anon511c6de30111::Resource523 	Resource (VkDescriptorType descriptorType_, const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue, bool useAABBs, deUint32 initialValue_, deUint32 numElements = 1u)
524 		: descriptorType	(descriptorType_)
525 		, resourceType      (toResourceType(descriptorType))
526 		, sampler           ()
527 		, imageWithMemory   ()
528 		, imageView         ()
529 		, bufferWithMemory  ()
530 		, bufferView        ()
531 		, asData            ()
532 		, initialValue      (initialValue_)
533 	{
534 		if (numElements != 1u)
535 			DE_ASSERT(resourceType == ResourceType::BUFFER);
536 
537 		switch (resourceType)
538 		{
539 		case ResourceType::SAMPLER:
540 			sampler = makeDefaultSampler(vkd, device);
541 			break;
542 
543 		case ResourceType::IMAGE:
544 			imageWithMemory = makeDefaultImage(vkd, device, alloc);
545 			imageView       = makeDefaultImageView(vkd, device, imageWithMemory->get());
546 			break;
547 
548 		case ResourceType::COMBINED_IMAGE_SAMPLER:
549 			sampler         = makeDefaultSampler(vkd, device);
550 			imageWithMemory = makeDefaultImage(vkd, device, alloc);
551 			imageView       = makeDefaultImageView(vkd, device, imageWithMemory->get());
552 			break;
553 
554 		case ResourceType::BUFFER:
555 			bufferWithMemory = makeDefaultBuffer(vkd, device, alloc, numElements);
556 			break;
557 
558 		case ResourceType::BUFFER_VIEW:
559 			bufferWithMemory = makeDefaultBuffer(vkd, device, alloc);
560 			bufferView       = makeDefaultBufferView(vkd, device, bufferWithMemory->get());
561 			break;
562 
563 		case ResourceType::ACCELERATION_STRUCTURE:
564 			{
565 				const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
566 				const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
567 				const auto cmdBuffer    = cmdBufferPtr.get();
568 				const bool triangles    = !useAABBs;
569 
570 				beginCommandBuffer(vkd, cmdBuffer);
571 				asData = makeDefaultAccelerationStructure(vkd, device, cmdBuffer, alloc, triangles, getAccelerationStructureOffsetX(initialValue));
572 				endCommandBuffer(vkd, cmdBuffer);
573 				submitCommandsAndWait(vkd, device, queue, cmdBuffer);
574 			}
575 			break;
576 
577 		default:
578 			DE_ASSERT(false);
579 			break;
580 		}
581 
582 		if (imageWithMemory || bufferWithMemory)
583 		{
584 			const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
585 			const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
586 			const auto cmdBuffer    = cmdBufferPtr.get();
587 
588 			if (imageWithMemory)
589 			{
590 				// Prepare staging buffer.
591 				const auto               bufferSize        = static_cast<VkDeviceSize>(sizeof(initialValue));
592 				const VkBufferUsageFlags bufferUsage       = (VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
593 				const auto               stagingBufferInfo = makeBufferCreateInfo(bufferSize, bufferUsage);
594 
595 				BufferWithMemory stagingBuffer(vkd, device, alloc, stagingBufferInfo, MemoryRequirement::HostVisible);
596 				auto& bufferAlloc = stagingBuffer.getAllocation();
597 				void* bufferData  = bufferAlloc.getHostPtr();
598 
599 				deMemcpy(bufferData, &initialValue, sizeof(initialValue));
600 				flushAlloc(vkd, device, bufferAlloc);
601 
602 				beginCommandBuffer(vkd, cmdBuffer);
603 
604 				// Transition and copy image.
605 				const auto copyRegion         = makeBufferImageCopy(makeExtent3D(1u, 1u, 1u),
606 																	makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
607 
608 				// Switch image to TRANSFER_DST_OPTIMAL before copying data to it.
609 				const auto subresourceRange   = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
610 
611 				const auto preTransferBarrier = makeImageMemoryBarrier(
612 					0u, VK_ACCESS_TRANSFER_WRITE_BIT,
613 					VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
614 					imageWithMemory->get(), subresourceRange);
615 
616 				vkd.cmdPipelineBarrier(
617 					cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
618 					0u, nullptr, 0u, nullptr, 1u, &preTransferBarrier);
619 
620 				// Copy data to image.
621 				vkd.cmdCopyBufferToImage(cmdBuffer, stagingBuffer.get(), imageWithMemory->get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copyRegion);
622 
623 				// Switch image to the GENERAL layout before reading or writing to it from shaders.
624 				const auto postTransferBarrier = makeImageMemoryBarrier(
625 					VK_ACCESS_TRANSFER_WRITE_BIT, kShaderAccess,
626 					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
627 					imageWithMemory->get(), subresourceRange);
628 
629 				vkd.cmdPipelineBarrier(
630 					cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u,
631 					0u, nullptr, 0u, nullptr, 1u, &postTransferBarrier);
632 
633 				endCommandBuffer(vkd, cmdBuffer);
634 				submitCommandsAndWait(vkd, device, queue, cmdBuffer);
635 			}
636 
637 			if (bufferWithMemory)
638 			{
639 				auto& bufferAlloc = bufferWithMemory->getAllocation();
640 				void* bufferData  = bufferAlloc.getHostPtr();
641 
642 				const std::vector<deUint32> bufferValues(numElements, initialValue);
643 				deMemcpy(bufferData, bufferValues.data(), de::dataSize(bufferValues));
644 				flushAlloc(vkd, device, bufferAlloc);
645 
646 				beginCommandBuffer(vkd, cmdBuffer);
647 
648 				// Make sure host writes happen before shader reads/writes. Note: this barrier is not needed in theory.
649 				const auto hostToShaderBarrier = makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, kShaderAccess);
650 
651 				vkd.cmdPipelineBarrier(
652 					cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0u,
653 					1u, &hostToShaderBarrier, 0u, nullptr, 0u, nullptr);
654 
655 				endCommandBuffer(vkd, cmdBuffer);
656 				submitCommandsAndWait(vkd, device, queue, cmdBuffer);
657 			}
658 		}
659 	}
660 
661 	// Remove problematic copy constructor.
662 	Resource (const Resource&) = delete;
663 
664 	// Make it movable.
Resourcevkt::BindingModel::__anon511c6de30111::Resource665 	Resource (Resource&& other) noexcept
666 		: descriptorType	(other.descriptorType)
667 		, resourceType      (other.resourceType)
668 		, sampler           (other.sampler)
669 		, imageWithMemory   (other.imageWithMemory.release())
670 		, imageView         (other.imageView)
671 		, bufferWithMemory  (other.bufferWithMemory.release())
672 		, bufferView        (other.bufferView)
673 		, asData			(std::move(other.asData))
674 		, initialValue      (other.initialValue)
675 	{}
676 
~Resourcevkt::BindingModel::__anon511c6de30111::Resource677 	~Resource ()
678 	{}
679 
makeWriteInfovkt::BindingModel::__anon511c6de30111::Resource680 	WriteInfo makeWriteInfo () const
681 	{
682 		using WriteInfoPtr = de::MovePtr<WriteInfo>;
683 
684 		WriteInfoPtr writeInfo;
685 
686 		switch (resourceType)
687 		{
688 		case ResourceType::SAMPLER:
689 			{
690 				const VkDescriptorImageInfo imageInfo = { sampler.get(), DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED };
691 				writeInfo = WriteInfoPtr (new WriteInfo(imageInfo));
692 			}
693 			break;
694 
695 		case ResourceType::IMAGE:
696 			{
697 				const VkDescriptorImageInfo imageInfo = { DE_NULL, imageView.get(), VK_IMAGE_LAYOUT_GENERAL };
698 				writeInfo = WriteInfoPtr (new WriteInfo(imageInfo));
699 			}
700 			break;
701 
702 		case ResourceType::COMBINED_IMAGE_SAMPLER:
703 			{
704 				const VkDescriptorImageInfo imageInfo = { sampler.get(), imageView.get(), VK_IMAGE_LAYOUT_GENERAL };
705 				writeInfo = WriteInfoPtr (new WriteInfo(imageInfo));
706 			}
707 			break;
708 
709 		case ResourceType::BUFFER:
710 			{
711 				const VkDescriptorBufferInfo bufferInfo = { bufferWithMemory->get(), 0ull, static_cast<VkDeviceSize>(sizeof(deUint32)) };
712 				writeInfo = WriteInfoPtr (new WriteInfo(bufferInfo));
713 			}
714 			break;
715 
716 		case ResourceType::BUFFER_VIEW:
717 			writeInfo = WriteInfoPtr (new WriteInfo(bufferView.get()));
718 			break;
719 
720 		case ResourceType::ACCELERATION_STRUCTURE:
721 			{
722 				VkWriteDescriptorSetAccelerationStructureKHR asWrite = initVulkanStructure();
723 				asWrite.accelerationStructureCount = 1u;
724 				asWrite.pAccelerationStructures    = asData.tlas.get()->getPtr();
725 				writeInfo = WriteInfoPtr (new WriteInfo(asWrite));
726 			}
727 			break;
728 
729 		default:
730 			DE_ASSERT(false);
731 			break;
732 		}
733 
734 		return *writeInfo;
735 	}
736 
getStoredValuevkt::BindingModel::__anon511c6de30111::Resource737 	tcu::Maybe<deUint32> getStoredValue (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue, deUint32 position = 0u) const
738 	{
739 		if (position != 0u)
740 			DE_ASSERT(static_cast<bool>(bufferWithMemory));
741 
742 		if (imageWithMemory || bufferWithMemory)
743 		{
744 			// Command pool and buffer.
745 			const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
746 			const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
747 			const auto cmdBuffer    = cmdBufferPtr.get();
748 
749 			if (imageWithMemory)
750 			{
751 				// Prepare staging buffer.
752 				deUint32                 result;
753 				const auto               bufferSize        = static_cast<VkDeviceSize>(sizeof(result));
754 				const VkBufferUsageFlags bufferUsage       = (VK_BUFFER_USAGE_TRANSFER_DST_BIT);
755 				const auto               stagingBufferInfo = makeBufferCreateInfo(bufferSize, bufferUsage);
756 
757 				BufferWithMemory stagingBuffer(vkd, device, alloc, stagingBufferInfo, MemoryRequirement::HostVisible);
758 				auto& bufferAlloc = stagingBuffer.getAllocation();
759 				void* bufferData  = bufferAlloc.getHostPtr();
760 
761 				// Copy image value to staging buffer.
762 				beginCommandBuffer(vkd, cmdBuffer);
763 
764 				// Make sure shader accesses happen before transfers and prepare image for transfer.
765 				const auto colorResourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
766 
767 				const auto preTransferBarrier = makeImageMemoryBarrier(
768 					kShaderAccess, VK_ACCESS_TRANSFER_READ_BIT,
769 					VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
770 					imageWithMemory->get(), colorResourceRange);
771 
772 				vkd.cmdPipelineBarrier(
773 					cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
774 					0u, nullptr, 0u, nullptr, 1u, &preTransferBarrier);
775 
776 				// Copy image contents to staging buffer.
777 				const auto copyRegion = makeBufferImageCopy(makeExtent3D(1u, 1u, 1u),
778 															makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
779 				vkd.cmdCopyImageToBuffer(cmdBuffer, imageWithMemory->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuffer.get(), 1u, &copyRegion);
780 
781 				// Make sure writes are visible from the host.
782 				const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
783 				vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postTransferBarrier, 0u, nullptr, 0u, nullptr);
784 
785 				endCommandBuffer(vkd, cmdBuffer);
786 				submitCommandsAndWait(vkd, device, queue, cmdBuffer);
787 
788 				// Get value from staging buffer.
789 				invalidateAlloc(vkd, device, bufferAlloc);
790 				deMemcpy(&result, bufferData, sizeof(result));
791 				return tcu::just(result);
792 			}
793 
794 			if (bufferWithMemory)
795 			{
796 				auto&       bufferAlloc = bufferWithMemory->getAllocation();
797 				auto        bufferData  = reinterpret_cast<const char*>(bufferAlloc.getHostPtr());
798 				deUint32    result;
799 
800 				// Make sure shader writes are visible from the host.
801 				beginCommandBuffer(vkd, cmdBuffer);
802 
803 				const auto shaderToHostBarrier = makeMemoryBarrier(kShaderAccess, VK_ACCESS_HOST_READ_BIT);
804 				vkd.cmdPipelineBarrier(
805 					cmdBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
806 					1u, &shaderToHostBarrier, 0u, nullptr, 0u, nullptr);
807 
808 				endCommandBuffer(vkd, cmdBuffer);
809 				submitCommandsAndWait(vkd, device, queue, cmdBuffer);
810 
811 				invalidateAlloc(vkd, device, bufferAlloc);
812 				deMemcpy(&result, bufferData + sizeof(deUint32) * static_cast<size_t>(position), sizeof(result));
813 				return tcu::just(result);
814 			}
815 		}
816 
817 		return tcu::Nothing;
818 	}
819 };
820 
821 struct BindingInterface
822 {
823 	// Minimum number of iterations to test all mutable types.
824 	virtual deUint32 maxTypes () const = 0;
825 
826 	// Types that will be used by the binding at a given iteration.
827 	virtual std::vector<VkDescriptorType> typesAtIteration (deUint32 iteration) const = 0;
828 
829 	// Binding's main type.
830 	virtual VkDescriptorType mainType () const = 0;
831 
832 	// Binding's list of mutable types, if present.
833 	virtual std::vector<VkDescriptorType> mutableTypes () const = 0;
834 
835 	// Descriptor count in the binding.
836 	virtual size_t size () const = 0;
837 
838 	// Is the binding an array binding?
839 	virtual bool isArray () const = 0;
840 
841 	// Is the binding an unbounded array?
842 	virtual bool isUnbounded () const = 0;
843 
844 	// Will the binding use different descriptor types in a given iteration?
needsAliasingvkt::BindingModel::__anon511c6de30111::BindingInterface845 	virtual bool needsAliasing (deUint32 iteration) const
846 	{
847 		const auto                 typesVec = typesAtIteration(iteration);
848 		std::set<VkDescriptorType> descTypes(begin(typesVec), end(typesVec));
849 		return (descTypes.size() > 1u);
850 	}
851 
852 	// Will the binding need aliasing on any iteration up to a given number?
needsAliasingUpTovkt::BindingModel::__anon511c6de30111::BindingInterface853 	virtual bool needsAliasingUpTo (deUint32 numIterations) const
854 	{
855 		std::vector<bool> needsAliasingFlags;
856 		needsAliasingFlags.reserve(numIterations);
857 
858 		for (deUint32 iter = 0u; iter < numIterations; ++iter)
859 			needsAliasingFlags.push_back(needsAliasing(iter));
860 
861 		return std::any_of(begin(needsAliasingFlags), end(needsAliasingFlags), [] (bool f) { return f; });
862 	}
863 
864 private:
hasDescriptorTypevkt::BindingModel::__anon511c6de30111::BindingInterface865 	virtual bool hasDescriptorType (deUint32 iteration, VkDescriptorType descriptorType) const
866 	{
867 		const auto typesVec = typesAtIteration(iteration);
868 		return (std::find(begin(typesVec), end(typesVec), descriptorType) != end(typesVec));
869 	}
870 
871 public:
872 	// Convert one particular binding to a mutable or non-mutable equivalent binding, returning the equivalent binding.
873 	virtual de::MovePtr<BindingInterface> toMutable (deUint32 iteration) const = 0;
874 	virtual de::MovePtr<BindingInterface> toNonMutable (deUint32 iteration) const = 0;
875 
876 	// Create resources needed to back up this binding.
877 	virtual std::vector<Resource> createResources (
878 		const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue,
879 		deUint32 iteration, bool useAABBs, deUint32 baseValue) const = 0;
880 
881 	// Get GLSL binding declarations. Note: no array size means no array, if size is < 0 it means unbounded array.
882 	virtual std::string glslDeclarations (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 inputAttachmentIdx, tcu::Maybe<deInt32> arraySize) const = 0;
883 
884 	// Get GLSL statements to check this binding.
885 	virtual std::string glslCheckStatements (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 baseValue, tcu::Maybe<deUint32> arrayIndex, bool usePushConstants) const = 0;
886 };
887 
888 // Represents a single binding that will be used in a test.
889 class SingleBinding : public BindingInterface
890 {
891 private:
892 	VkDescriptorType              type;             // The descriptor type.
893 	std::vector<VkDescriptorType> mutableTypesVec;  // The types that will be used for each iteration of a test if mutable.
894 
895 public:
SingleBinding(VkDescriptorType type_,std::vector<VkDescriptorType> mutableTypes_)896 	SingleBinding (VkDescriptorType type_, std::vector<VkDescriptorType> mutableTypes_)
897 		: type              (type_)
898 		, mutableTypesVec   (std::move(mutableTypes_))
899 	{
900 		static const auto kForbiddenMutableTypes = getForbiddenMutableTypes();
901 		const auto        kBeginForbidden        = begin(kForbiddenMutableTypes);
902 		const auto        kEndForbidden          = end(kForbiddenMutableTypes);
903 
904 		// For release builds.
905 		DE_UNREF(kBeginForbidden);
906 		DE_UNREF(kEndForbidden);
907 
908 		if (type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
909 		{
910 			DE_ASSERT(mutableTypesVec.empty());
911 		}
912 		else
913 		{
914 			DE_ASSERT(!mutableTypesVec.empty());
915 			DE_ASSERT(std::none_of(begin(mutableTypesVec), end(mutableTypesVec),
916 			                       [&kBeginForbidden, &kEndForbidden] (VkDescriptorType t) -> bool {
917 				                       return std::find(kBeginForbidden, kEndForbidden, t) != kEndForbidden;
918 			                       }));
919 		}
920 	}
921 
maxTypes() const922 	deUint32 maxTypes () const override
923 	{
924 		if (type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
925 			return 1u;
926 		const auto vecSize = mutableTypesVec.size();
927 		DE_ASSERT(vecSize <= std::numeric_limits<deUint32>::max());
928 		return static_cast<deUint32>(vecSize);
929 	}
930 
typeAtIteration(deUint32 iteration) const931 	VkDescriptorType typeAtIteration (deUint32 iteration) const
932 	{
933 		return typesAtIteration(iteration)[0];
934 	}
935 
usedTypes() const936 	std::vector<VkDescriptorType> usedTypes () const
937 	{
938 		if (type != VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
939 			return std::vector<VkDescriptorType>(1u, type);
940 		return mutableTypesVec;
941 	}
942 
typesAtIteration(deUint32 iteration) const943 	std::vector<VkDescriptorType> typesAtIteration (deUint32 iteration) const override
944 	{
945 		const auto typesVec = usedTypes();
946 		return std::vector<VkDescriptorType>(1u, typesVec[static_cast<size_t>(iteration) % typesVec.size()]);
947 	}
948 
mainType() const949 	VkDescriptorType mainType () const override
950 	{
951 		return type;
952 	}
953 
mutableTypes() const954 	std::vector<VkDescriptorType> mutableTypes () const override
955 	{
956 		return mutableTypesVec;
957 	}
958 
size() const959 	size_t size () const override
960 	{
961 		return size_t{1u};
962 	}
963 
isArray() const964 	bool isArray () const override
965 	{
966 		return false;
967 	}
968 
isUnbounded() const969 	bool isUnbounded () const override
970 	{
971 		return false;
972 	}
973 
toMutable(deUint32 iteration) const974 	de::MovePtr<BindingInterface> toMutable (deUint32 iteration) const override
975 	{
976 		DE_UNREF(iteration);
977 
978 		static const auto kMandatoryMutableTypeFlags = toDescriptorTypeFlags(getMandatoryMutableTypes());
979 		if (type == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
980 		{
981 			const auto descFlags = (toDescriptorTypeFlags(mutableTypesVec) | kMandatoryMutableTypeFlags);
982 			return de::MovePtr<BindingInterface>(new SingleBinding(type, toDescriptorTypeVector(descFlags)));
983 		}
984 
985 		// Make sure it's not a forbidden mutable type.
986 		static const auto kForbiddenMutableTypes = getForbiddenMutableTypes();
987 		DE_ASSERT(std::find(begin(kForbiddenMutableTypes), end(kForbiddenMutableTypes), type) == end(kForbiddenMutableTypes));
988 
989 		// Convert the binding to mutable using a wider set of descriptor types if possible, including the binding type.
990 		const auto descFlags = (kMandatoryMutableTypeFlags | toDescriptorTypeFlagBit(type));
991 
992 		return de::MovePtr<BindingInterface>(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, toDescriptorTypeVector(descFlags)));
993 	}
994 
toNonMutable(deUint32 iteration) const995 	de::MovePtr<BindingInterface> toNonMutable (deUint32 iteration) const override
996 	{
997 		return de::MovePtr<BindingInterface>(new SingleBinding(typeAtIteration(iteration), std::vector<VkDescriptorType>()));
998 	}
999 
createResources(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,deUint32 qIndex,VkQueue queue,deUint32 iteration,bool useAABBs,deUint32 baseValue) const1000 	std::vector<Resource> createResources (
1001 		const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue,
1002 		deUint32 iteration, bool useAABBs, deUint32 baseValue) const override
1003 	{
1004 		const auto descriptorType = typeAtIteration(iteration);
1005 
1006 		std::vector<Resource> resources;
1007 		resources.emplace_back(descriptorType, vkd, device, alloc, qIndex, queue, useAABBs, baseValue);
1008 		return resources;
1009 	}
1010 
glslDeclarations(deUint32 iteration,deUint32 setNum,deUint32 bindingNum,deUint32 inputAttachmentIdx,tcu::Maybe<deInt32> arraySize) const1011 	std::string glslDeclarations (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 inputAttachmentIdx, tcu::Maybe<deInt32> arraySize) const override
1012 	{
1013 		const auto         descriptorType = typeAtIteration(iteration);
1014 		const std::string  arraySuffix    = ((static_cast<bool>(arraySize)) ? ((arraySize.get() < 0) ? "[]" : ("[" + de::toString(arraySize.get()) + "]")) : "");
1015 		const std::string  layoutAttribs  = "set=" + de::toString(setNum) + ", binding=" + de::toString(bindingNum);
1016 		const std::string  bindingSuffix  = "_" + de::toString(setNum) + "_" + de::toString(bindingNum);
1017 		const std::string  nameSuffix     = bindingSuffix + arraySuffix;
1018 		std::ostringstream declarations;
1019 
1020 		declarations << "layout (";
1021 
1022 		switch (descriptorType)
1023 		{
1024 		case VK_DESCRIPTOR_TYPE_SAMPLER:
1025 			declarations << layoutAttribs << ") uniform sampler sampler" << nameSuffix;
1026 			break;
1027 
1028 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
1029 			declarations << layoutAttribs << ") uniform usampler2D combinedSampler" << nameSuffix;
1030 			break;
1031 
1032 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1033 			declarations << layoutAttribs << ") uniform utexture2D sampledImage" << nameSuffix;
1034 			break;
1035 
1036 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1037 			declarations << layoutAttribs << ") uniform uboBlock" << bindingSuffix << " { uint val; } ubo" << nameSuffix;
1038 			break;
1039 
1040 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1041 			declarations << layoutAttribs << ") buffer sboBlock" << bindingSuffix << " { uint val; } ssbo" << nameSuffix;
1042 			break;
1043 
1044 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1045 			declarations << layoutAttribs << ") uniform utextureBuffer uniformTexel" << nameSuffix;
1046 			break;
1047 
1048 		case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1049 			declarations << layoutAttribs << ", r32ui) uniform uimageBuffer storageTexel" << nameSuffix;
1050 			break;
1051 
1052 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1053 			declarations << layoutAttribs << ", r32ui) uniform uimage2D storageImage" << nameSuffix;
1054 			break;
1055 
1056 		case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
1057 			declarations << layoutAttribs << ", input_attachment_index=" << inputAttachmentIdx << ") uniform usubpassInput inputAttachment" << nameSuffix;
1058 			break;
1059 
1060 		case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
1061 			declarations << layoutAttribs << ") uniform accelerationStructureEXT accelerationStructure" << nameSuffix;
1062 			break;
1063 
1064 		default:
1065 			DE_ASSERT(false);
1066 			break;
1067 		}
1068 
1069 		declarations << ";\n";
1070 
1071 		return declarations.str();
1072 	}
1073 
glslCheckStatements(deUint32 iteration,deUint32 setNum,deUint32 bindingNum,deUint32 baseValue_,tcu::Maybe<deUint32> arrayIndex,bool usePushConstants) const1074 	std::string glslCheckStatements (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 baseValue_, tcu::Maybe<deUint32> arrayIndex, bool usePushConstants) const override
1075 	{
1076 		const auto        descriptorType = typeAtIteration(iteration);
1077 		const std::string bindingSuffix  = "_" + de::toString(setNum) + "_" + de::toString(bindingNum);
1078 
1079 		std::string indexSuffix;
1080 		if (arrayIndex)
1081 		{
1082 			indexSuffix = de::toString(arrayIndex.get());
1083 			if (usePushConstants)
1084 				indexSuffix += " + pc.zero";
1085 			indexSuffix = "[" + indexSuffix + "]";
1086 		}
1087 
1088 		const std::string nameSuffix         = bindingSuffix + indexSuffix;
1089 		const std::string baseValue          = toHex(baseValue_);
1090 		const std::string externalImageValue = toHex(getExternalSampledImageValue());
1091 		const std::string mask               = toHex(getStoredValueMask());
1092 
1093 		std::ostringstream checks;
1094 
1095 		// Note: all of these depend on an external anyError uint variable.
1096 		switch (descriptorType)
1097 		{
1098 		case VK_DESCRIPTOR_TYPE_SAMPLER:
1099 			// Note this depends on an "externalSampledImage" binding.
1100 			checks << "    {\n";
1101 			checks << "      uint readValue = texture(usampler2D(externalSampledImage, sampler" << nameSuffix << "), vec2(0, 0)).r;\n";
1102 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1103 			checks << "      anyError |= ((readValue == " << externalImageValue << ") ? 0u : 1u);\n";
1104 			//checks << "      anyError = readValue;\n";
1105 			checks << "    }\n";
1106 			break;
1107 
1108 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
1109 			checks << "    {\n";
1110 			checks << "      uint readValue = texture(combinedSampler" << nameSuffix << ", vec2(0, 0)).r;\n";
1111 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1112 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1113 			//checks << "      anyError = readValue;\n";
1114 			checks << "    }\n";
1115 			break;
1116 
1117 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
1118 			// Note this depends on an "externalSampler" binding.
1119 			checks << "    {\n";
1120 			checks << "      uint readValue = texture(usampler2D(sampledImage" << nameSuffix << ", externalSampler), vec2(0, 0)).r;\n";
1121 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1122 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1123 			//checks << "      anyError = readValue;\n";
1124 			checks << "    }\n";
1125 			break;
1126 
1127 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1128 			checks << "    {\n";
1129 			checks << "      uint readValue = ubo" << nameSuffix << ".val;\n";
1130 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1131 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1132 			//checks << "      anyError = readValue;\n";
1133 			checks << "    }\n";
1134 			break;
1135 
1136 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1137 			checks << "    {\n";
1138 			checks << "      uint readValue = ssbo" << nameSuffix << ".val;\n";
1139 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1140 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1141 			//checks << "      anyError = readValue;\n";
1142 			// Check writes.
1143 			checks << "      ssbo" << nameSuffix << ".val = (readValue | " << mask << ");\n";
1144 			checks << "    }\n";
1145 			break;
1146 
1147 		case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
1148 			checks << "    {\n";
1149 			checks << "      uint readValue = texelFetch(uniformTexel" << nameSuffix << ", 0).x;\n";
1150 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1151 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1152 			//checks << "      anyError = readValue;\n";
1153 			checks << "    }\n";
1154 			break;
1155 
1156 		case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
1157 			checks << "    {\n";
1158 			checks << "      uint readValue = imageLoad(storageTexel" << nameSuffix << ", 0).x;\n";
1159 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1160 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1161 			//checks << "      anyError = readValue;\n";
1162 			checks << "      readValue |= " << mask << ";\n";
1163 			// Check writes.
1164 			checks << "      imageStore(storageTexel" << nameSuffix << ", 0, uvec4(readValue, 0, 0, 0));\n";
1165 			checks << "    }\n";
1166 			break;
1167 
1168 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
1169 			checks << "    {\n";
1170 			checks << "      uint readValue = imageLoad(storageImage" << nameSuffix << ", ivec2(0, 0)).x;\n";
1171 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1172 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1173 			//checks << "      anyError = readValue;\n";
1174 			checks << "      readValue |= " << mask << ";\n";
1175 			// Check writes.
1176 			checks << "      imageStore(storageImage" << nameSuffix << ", ivec2(0, 0), uvec4(readValue, 0, 0, 0));\n";
1177 			checks << "    }\n";
1178 			break;
1179 
1180 		case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
1181 			checks << "    {\n";
1182 			checks << "      uint readValue = subpassLoad(inputAttachment" << nameSuffix << ").x;\n";
1183 			checks << "      debugPrintfEXT(\"iteration-" << iteration << nameSuffix << ": 0x%xu\\n\", readValue);\n";
1184 			checks << "      anyError |= ((readValue == " << baseValue << ") ? 0u : 1u);\n";
1185 			//checks << "      anyError = readValue;\n";
1186 			checks << "    }\n";
1187 			break;
1188 
1189 		case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
1190 			checks << "    {\n";
1191 			checks << "      const uint cullMask = 0xFF;\n";
1192 			checks << "      const vec3 origin = vec3(" << getAccelerationStructureOffsetX(baseValue_) << ".0, 0.0, 0.0);\n";
1193 			checks << "      const vec3 direction = vec3(0.0, 0.0, 1.0);\n";
1194 			checks << "      const float tmin = 1.0;\n";
1195 			checks << "      const float tmax = 10.0;\n";
1196 			checks << "      uint candidateFound = 0u;\n";
1197 			checks << "      rayQueryEXT rq;\n";
1198 			checks << "      rayQueryInitializeEXT(rq, accelerationStructure" << nameSuffix << ", gl_RayFlagsNoneEXT, cullMask, origin, tmin, direction, tmax);\n";
1199 			checks << "      while (rayQueryProceedEXT(rq)) {\n";
1200 			checks << "        const uint candidateType = rayQueryGetIntersectionTypeEXT(rq, false);\n";
1201 			checks << "        if (candidateType == gl_RayQueryCandidateIntersectionTriangleEXT || candidateType == gl_RayQueryCandidateIntersectionAABBEXT) {\n";
1202 			checks << "          candidateFound = 1u;\n";
1203 			checks << "        }\n";
1204 			checks << "      }\n";
1205 			checks << "      anyError |= ((candidateFound == 1u) ? 0u : 1u);\n";
1206 			checks << "    }\n";
1207 			break;
1208 
1209 		default:
1210 			DE_ASSERT(false);
1211 			break;
1212 		}
1213 
1214 		return checks.str();
1215 	}
1216 };
1217 
1218 // Represents an array of bindings. Individual bindings are stored as SingleBindings because each one of them may take a different
1219 // type in each iteration (i.e. they can all have different descriptor type vectors).
1220 class ArrayBinding : public BindingInterface
1221 {
1222 private:
1223 	bool                       unbounded;
1224 	std::vector<SingleBinding> bindings;
1225 
1226 public:
ArrayBinding(bool unbounded_,std::vector<SingleBinding> bindings_)1227 	ArrayBinding (bool unbounded_, std::vector<SingleBinding> bindings_)
1228 		: unbounded (unbounded_)
1229 		, bindings  (std::move(bindings_))
1230 	{
1231 		// We need to check all single bindings have the same effective type, even if mutable descriptors have different orders.
1232 		DE_ASSERT(!bindings.empty());
1233 
1234 		std::set<VkDescriptorType>    basicTypes;
1235 		std::set<DescriptorTypeFlags> bindingTypes;
1236 
1237 		for (const auto& b : bindings)
1238 		{
1239 			basicTypes.insert(b.mainType());
1240 			bindingTypes.insert(toDescriptorTypeFlags(b.usedTypes()));
1241 		}
1242 
1243 		DE_ASSERT(basicTypes.size() == 1u);
1244 		DE_ASSERT(bindingTypes.size() == 1u);
1245 
1246 		// For release builds.
1247 		DE_UNREF(basicTypes);
1248 		DE_UNREF(bindingTypes);
1249 	}
1250 
maxTypes() const1251 	deUint32 maxTypes () const override
1252 	{
1253 		// Each binding may have the same effective type but a different number of iterations due to repeated types.
1254 		std::vector<size_t> bindingSizes;
1255 		bindingSizes.reserve(bindings.size());
1256 
1257 		std::transform(begin(bindings), end(bindings), std::back_inserter(bindingSizes),
1258 		               [] (const SingleBinding& b) { return b.usedTypes().size(); });
1259 
1260 		const auto maxElement = std::max_element(begin(bindingSizes), end(bindingSizes));
1261 		DE_ASSERT(maxElement != end(bindingSizes));
1262 		DE_ASSERT(*maxElement <= std::numeric_limits<deUint32>::max());
1263 		return static_cast<deUint32>(*maxElement);
1264 	}
1265 
typesAtIteration(deUint32 iteration) const1266 	std::vector<VkDescriptorType> typesAtIteration (deUint32 iteration) const override
1267 	{
1268 		std::vector<VkDescriptorType> result;
1269 		result.reserve(bindings.size());
1270 
1271 		for (const auto& b : bindings)
1272 			result.push_back(b.typeAtIteration(iteration));
1273 
1274 		return result;
1275 	}
1276 
mainType() const1277 	VkDescriptorType mainType () const override
1278 	{
1279 		return bindings[0].mainType();
1280 	}
1281 
mutableTypes() const1282 	std::vector<VkDescriptorType> mutableTypes () const override
1283 	{
1284 		return bindings[0].mutableTypes();
1285 	}
1286 
size() const1287 	size_t size () const override
1288 	{
1289 		return bindings.size();
1290 	}
1291 
isArray() const1292 	bool isArray () const override
1293 	{
1294 		return true;
1295 	}
1296 
isUnbounded() const1297 	bool isUnbounded () const override
1298 	{
1299 		return unbounded;
1300 	}
1301 
toMutable(deUint32 iteration) const1302 	de::MovePtr<BindingInterface> toMutable (deUint32 iteration) const override
1303 	{
1304 		// Replicate the first binding once converted, as all are equivalent.
1305 		const auto                       firstBindingPtr = bindings[0].toMutable(iteration);
1306 		const auto                       firstBinding    = *dynamic_cast<SingleBinding*>(firstBindingPtr.get());
1307 		const std::vector<SingleBinding> newBindings     (bindings.size(), firstBinding);
1308 
1309 		return de::MovePtr<BindingInterface>(new ArrayBinding(unbounded, newBindings));
1310 	}
1311 
toNonMutable(deUint32 iteration) const1312 	de::MovePtr<BindingInterface> toNonMutable (deUint32 iteration) const override
1313 	{
1314 		// Make sure this binding can be converted to nonmutable for a given iteration.
1315 		DE_ASSERT(!needsAliasing(iteration));
1316 
1317 		// We could use each SingleBinding's toNonMutable(), but this is the same.
1318 		const auto                       descType       = bindings[0].typeAtIteration(iteration);
1319 		const SingleBinding              firstBinding   (descType, std::vector<VkDescriptorType>());
1320 		const std::vector<SingleBinding> newBindings    (bindings.size(), firstBinding);
1321 
1322 		return de::MovePtr<BindingInterface>(new ArrayBinding(unbounded, newBindings));
1323 	}
1324 
createResources(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,deUint32 qIndex,VkQueue queue,deUint32 iteration,bool useAABBs,deUint32 baseValue) const1325 	std::vector<Resource> createResources (
1326 		const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue,
1327 		deUint32 iteration, bool useAABBs, deUint32 baseValue) const override
1328 	{
1329 		std::vector<Resource> resources;
1330 		const auto            numBindings = static_cast<deUint32>(bindings.size());
1331 
1332 		for (deUint32 i = 0u; i < numBindings; ++i)
1333 		{
1334 			auto resourceVec = bindings[i].createResources(vkd, device, alloc, qIndex, queue, iteration, useAABBs, baseValue + i);
1335 			resources.emplace_back(std::move(resourceVec[0]));
1336 		}
1337 
1338 		return resources;
1339 	}
1340 
1341 	// We will ignore the array size parameter.
glslDeclarations(deUint32 iteration,deUint32 setNum,deUint32 bindingNum,deUint32 inputAttachmentIdx,tcu::Maybe<deInt32> arraySize) const1342 	std::string glslDeclarations (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 inputAttachmentIdx, tcu::Maybe<deInt32> arraySize) const override
1343 	{
1344 		const auto descriptorCount = bindings.size();
1345 		const auto arraySizeVal    = (isUnbounded() ? tcu::just(deInt32{-1}) : tcu::just(static_cast<deInt32>(descriptorCount)));
1346 
1347 		DE_UNREF(arraySize);
1348 		DE_ASSERT(descriptorCount < static_cast<size_t>(std::numeric_limits<deInt32>::max()));
1349 
1350 		// Maybe a single declaration is enough.
1351 		if (!needsAliasing(iteration))
1352 			return bindings[0].glslDeclarations(iteration, setNum, bindingNum, inputAttachmentIdx, arraySizeVal);
1353 
1354 		// Aliasing needed. Avoid reusing types.
1355 		const auto                 descriptorTypes = typesAtIteration(iteration);
1356 		std::set<VkDescriptorType> usedTypes;
1357 		std::ostringstream         declarations;
1358 
1359 		for (size_t descriptorIdx = 0u; descriptorIdx < descriptorCount; ++descriptorIdx)
1360 		{
1361 			const auto& descriptorType = descriptorTypes[descriptorIdx];
1362 			if (usedTypes.count(descriptorType) > 0)
1363 				continue;
1364 
1365 			usedTypes.insert(descriptorType);
1366 			declarations << bindings[descriptorIdx].glslDeclarations(iteration, setNum, bindingNum, inputAttachmentIdx, arraySizeVal);
1367 		}
1368 
1369 		return declarations.str();
1370 	}
1371 
glslCheckStatements(deUint32 iteration,deUint32 setNum,deUint32 bindingNum,deUint32 baseValue_,tcu::Maybe<deUint32> arrayIndex,bool usePushConstants) const1372 	std::string glslCheckStatements (deUint32 iteration, deUint32 setNum, deUint32 bindingNum, deUint32 baseValue_, tcu::Maybe<deUint32> arrayIndex, bool usePushConstants) const override
1373 	{
1374 		DE_ASSERT(!arrayIndex);
1375 		DE_UNREF(arrayIndex); // For release builds.
1376 
1377 		std::ostringstream checks;
1378 		const auto         numDescriptors = static_cast<deUint32>(bindings.size());
1379 
1380 		for (deUint32 descriptorIdx  = 0u; descriptorIdx < numDescriptors; ++descriptorIdx)
1381 		{
1382 			const auto& binding = bindings[descriptorIdx];
1383 			checks << binding.glslCheckStatements(iteration, setNum, bindingNum, baseValue_ + descriptorIdx, tcu::just(descriptorIdx), usePushConstants);
1384 		}
1385 
1386 		return checks.str();
1387 	}
1388 };
1389 
1390 class DescriptorSet;
1391 
1392 using DescriptorSetPtr = de::SharedPtr<DescriptorSet>;
1393 
1394 class DescriptorSet
1395 {
1396 public:
1397 	using BindingInterfacePtr   = de::MovePtr<BindingInterface>;
1398 	using BindingPtrVector      = std::vector<BindingInterfacePtr>;
1399 
1400 private:
1401 	BindingPtrVector bindings;
1402 
1403 public:
DescriptorSet(BindingPtrVector & bindings_)1404 	explicit DescriptorSet (BindingPtrVector& bindings_)
1405 		: bindings(std::move(bindings_))
1406 	{
1407 		DE_ASSERT(!bindings.empty());
1408 	}
1409 
numBindings() const1410 	size_t numBindings () const
1411 	{
1412 		return bindings.size();
1413 	}
1414 
getBinding(size_t bindingIdx) const1415 	const BindingInterface* getBinding (size_t bindingIdx) const
1416 	{
1417 		return bindings.at(bindingIdx).get();
1418 	}
1419 
1420 	// Maximum number of descriptor types used by any binding in the set.
maxTypes() const1421 	deUint32 maxTypes () const
1422 	{
1423 		std::vector<deUint32> maxSizes;
1424 		maxSizes.reserve(bindings.size());
1425 
1426 		std::transform(begin(bindings), end(bindings), std::back_inserter(maxSizes),
1427 		               [] (const BindingInterfacePtr& b) { return b->maxTypes(); });
1428 
1429 		const auto maxElement = std::max_element(begin(maxSizes), end(maxSizes));
1430 		DE_ASSERT(maxElement != end(maxSizes));
1431 		return *maxElement;
1432 	}
1433 
1434 	// Create another descriptor set that can be the source for copies when setting descriptor values.
genSourceSet(SourceSetStrategy strategy,deUint32 iteration) const1435 	DescriptorSetPtr genSourceSet (SourceSetStrategy strategy, deUint32 iteration) const
1436 	{
1437 		BindingPtrVector newBindings;
1438 		for (const auto& b : bindings)
1439 		{
1440 			if (strategy == SourceSetStrategy::MUTABLE)
1441 				newBindings.push_back(b->toMutable(iteration));
1442 			else
1443 				newBindings.push_back(b->toNonMutable(iteration));
1444 		}
1445 
1446 		return DescriptorSetPtr(new DescriptorSet(newBindings));
1447 	}
1448 
1449 	// Makes a descriptor pool that can be used when allocating descriptors for this set.
makeDescriptorPool(const DeviceInterface & vkd,VkDevice device,PoolMutableStrategy strategy,VkDescriptorPoolCreateFlags flags) const1450 	Move<VkDescriptorPool> makeDescriptorPool (const DeviceInterface& vkd, VkDevice device, PoolMutableStrategy strategy, VkDescriptorPoolCreateFlags flags) const
1451 	{
1452 		std::vector<VkDescriptorPoolSize>             poolSizes;
1453 		std::vector<std::vector<VkDescriptorType>>    mutableTypesVec;
1454 		std::vector<VkMutableDescriptorTypeListVALVE> mutableTypeLists;
1455 
1456 		// Make vector element addresses stable.
1457 		const auto bindingCount = numBindings();
1458 		poolSizes.reserve(bindingCount);
1459 		mutableTypesVec.reserve(bindingCount);
1460 		mutableTypeLists.reserve(bindingCount);
1461 
1462 		for (const auto& b : bindings)
1463 		{
1464 			const auto                 mainType = b->mainType();
1465 			const VkDescriptorPoolSize poolSize = {
1466 				mainType,
1467 				static_cast<deUint32>(b->size()),
1468 			};
1469 			poolSizes.push_back(poolSize);
1470 
1471 			if (strategy == PoolMutableStrategy::KEEP_TYPES || strategy == PoolMutableStrategy::EXPAND_TYPES)
1472 			{
1473 				if (mainType == VK_DESCRIPTOR_TYPE_MUTABLE_VALVE)
1474 				{
1475 					if (strategy == PoolMutableStrategy::KEEP_TYPES)
1476 					{
1477 						mutableTypesVec.emplace_back(b->mutableTypes());
1478 					}
1479 					else
1480 					{
1481 						// Expand the type list with the mandatory types.
1482 						static const auto mandatoryTypesFlags = toDescriptorTypeFlags(getMandatoryMutableTypes());
1483 						const auto        bindingTypes        = toDescriptorTypeVector(mandatoryTypesFlags | toDescriptorTypeFlags(b->mutableTypes()));
1484 
1485 						mutableTypesVec.emplace_back(bindingTypes);
1486 					}
1487 
1488 					const auto& lastVec = mutableTypesVec.back();
1489 					const VkMutableDescriptorTypeListVALVE typeList = { static_cast<deUint32>(lastVec.size()), de::dataOrNull(lastVec) };
1490 					mutableTypeLists.push_back(typeList);
1491 				}
1492 				else
1493 				{
1494 					const VkMutableDescriptorTypeListVALVE typeList = { 0u, nullptr };
1495 					mutableTypeLists.push_back(typeList);
1496 				}
1497 			}
1498 			else if (strategy == PoolMutableStrategy::NO_TYPES)
1499 				; // Do nothing, we will not use any type list.
1500 			else
1501 				DE_ASSERT(false);
1502 		}
1503 
1504 		VkDescriptorPoolCreateInfo poolCreateInfo = initVulkanStructure();
1505 
1506 		poolCreateInfo.maxSets       = 1u;
1507 		poolCreateInfo.flags         = flags;
1508 		poolCreateInfo.poolSizeCount = static_cast<deUint32>(poolSizes.size());
1509 		poolCreateInfo.pPoolSizes    = de::dataOrNull(poolSizes);
1510 
1511 		VkMutableDescriptorTypeCreateInfoVALVE mutableInfo = initVulkanStructure();
1512 
1513 		if (strategy == PoolMutableStrategy::KEEP_TYPES || strategy == PoolMutableStrategy::EXPAND_TYPES)
1514 		{
1515 			mutableInfo.mutableDescriptorTypeListCount = static_cast<deUint32>(mutableTypeLists.size());
1516 			mutableInfo.pMutableDescriptorTypeLists    = de::dataOrNull(mutableTypeLists);
1517 			poolCreateInfo.pNext                       = &mutableInfo;
1518 		}
1519 
1520 		return createDescriptorPool(vkd, device, &poolCreateInfo);
1521 	}
1522 
1523 private:
1524 	// Building the descriptor set layout create info structure is cumbersome, so we'll reuse the same procedure to check support
1525 	// and create the layout. This structure contains the result. "supported" is created as an enum to avoid the Move<> to bool
1526 	// conversion cast in the contructors.
1527 	struct DescriptorSetLayoutResult
1528 	{
1529 		enum class LayoutSupported { NO = 0, YES };
1530 
1531 		LayoutSupported             supported;
1532 		Move<VkDescriptorSetLayout> layout;
1533 
DescriptorSetLayoutResultvkt::BindingModel::__anon511c6de30111::DescriptorSet::DescriptorSetLayoutResult1534 		explicit DescriptorSetLayoutResult (Move<VkDescriptorSetLayout>&& layout_)
1535 			: supported (LayoutSupported::YES)
1536 			, layout    (layout_)
1537 		{}
1538 
DescriptorSetLayoutResultvkt::BindingModel::__anon511c6de30111::DescriptorSet::DescriptorSetLayoutResult1539 		explicit DescriptorSetLayoutResult (LayoutSupported supported_)
1540 			: supported (supported_)
1541 			, layout    ()
1542 		{}
1543 	};
1544 
makeOrCheckDescriptorSetLayout(bool checkOnly,const DeviceInterface & vkd,VkDevice device,VkShaderStageFlags stageFlags,VkDescriptorSetLayoutCreateFlags createFlags) const1545 	DescriptorSetLayoutResult makeOrCheckDescriptorSetLayout (bool checkOnly, const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stageFlags, VkDescriptorSetLayoutCreateFlags createFlags) const
1546 	{
1547 		const auto                                    numIterations = maxTypes();
1548 		std::vector<VkDescriptorSetLayoutBinding>     bindingsVec;
1549 		std::vector<std::vector<VkDescriptorType>>    mutableTypesVec;
1550 		std::vector<VkMutableDescriptorTypeListVALVE> mutableTypeLists;
1551 
1552 		// Make vector element addresses stable.
1553 		const auto bindingCount = numBindings();
1554 		bindingsVec.reserve(bindingCount);
1555 		mutableTypesVec.reserve(bindingCount);
1556 		mutableTypeLists.reserve(bindingCount);
1557 
1558 		for (size_t bindingIdx = 0u; bindingIdx < bindings.size(); ++bindingIdx)
1559 		{
1560 			const auto& binding = bindings[bindingIdx];
1561 			const auto mainType = binding->mainType();
1562 
1563 			const VkDescriptorSetLayoutBinding layoutBinding = {
1564 				static_cast<deUint32>(bindingIdx),        //    deUint32			binding;
1565 				mainType,                                 //    VkDescriptorType	descriptorType;
1566 				static_cast<deUint32>(binding->size()),   //    deUint32			descriptorCount;
1567 				stageFlags,                               //    VkShaderStageFlags	stageFlags;
1568 				nullptr,                                  //    const VkSampler*	pImmutableSamplers;
1569 			};
1570 			bindingsVec.push_back(layoutBinding);
1571 
1572 			// This list may be empty for non-mutable types, which is fine.
1573 			mutableTypesVec.push_back(binding->mutableTypes());
1574 			const auto& lastVec = mutableTypesVec.back();
1575 
1576 			const VkMutableDescriptorTypeListVALVE typeList = {
1577 				static_cast<deUint32>(lastVec.size()),  //  deUint32				descriptorTypeCount;
1578 				de::dataOrNull(lastVec),                //  const VkDescriptorType*	pDescriptorTypes;
1579 			};
1580 			mutableTypeLists.push_back(typeList);
1581 		}
1582 
1583 		// Make sure to include the variable descriptor count and/or update after bind binding flags.
1584 		const bool        updateAfterBind = ((createFlags & VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT) != 0u);
1585 		bool              lastIsUnbounded = false;
1586 		bool              aliasingNeded   = false;
1587 		std::vector<bool> bindingNeedsAliasing(bindings.size(), false);
1588 
1589 		for (size_t bindingIdx = 0; bindingIdx < bindings.size(); ++bindingIdx)
1590 		{
1591 			if (bindingIdx < bindings.size() - 1)
1592 				DE_ASSERT(!bindings[bindingIdx]->isUnbounded());
1593 			else
1594 				lastIsUnbounded = bindings[bindingIdx]->isUnbounded();
1595 
1596 			if (bindings[bindingIdx]->needsAliasingUpTo(numIterations))
1597 			{
1598 				bindingNeedsAliasing[bindingIdx] = true;
1599 				aliasingNeded = true;
1600 			}
1601 		}
1602 
1603 		using FlagsCreateInfoPtr = de::MovePtr<VkDescriptorSetLayoutBindingFlagsCreateInfo>;
1604 		using BindingFlagsVecPtr = de::MovePtr<std::vector<VkDescriptorBindingFlags>>;
1605 
1606 		FlagsCreateInfoPtr flagsCreateInfo;
1607 		BindingFlagsVecPtr bindingFlagsVec;
1608 
1609 		if (updateAfterBind || lastIsUnbounded || aliasingNeded)
1610 		{
1611 			flagsCreateInfo = FlagsCreateInfoPtr(new VkDescriptorSetLayoutBindingFlagsCreateInfo);
1612 			*flagsCreateInfo = initVulkanStructure();
1613 
1614 			bindingFlagsVec = BindingFlagsVecPtr(new std::vector<VkDescriptorBindingFlags>(bindingsVec.size(), (updateAfterBind ? VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT : 0)));
1615 			if (lastIsUnbounded)
1616 				bindingFlagsVec->back() |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT;
1617 
1618 			for (size_t bindingIdx = 0; bindingIdx < bindings.size(); ++bindingIdx)
1619 			{
1620 				if (bindingNeedsAliasing[bindingIdx])
1621 					bindingFlagsVec->at(bindingIdx) |= VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT;
1622 			}
1623 
1624 			flagsCreateInfo->bindingCount  = static_cast<deUint32>(bindingFlagsVec->size());
1625 			flagsCreateInfo->pBindingFlags = de::dataOrNull(*bindingFlagsVec);
1626 		}
1627 
1628 		const VkMutableDescriptorTypeCreateInfoVALVE createInfoValve = {
1629 			VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE,
1630 			flagsCreateInfo.get(),
1631 			static_cast<deUint32>(mutableTypeLists.size()),
1632 			de::dataOrNull(mutableTypeLists),
1633 		};
1634 
1635 		const VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {
1636 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,    //  VkStructureType						sType;
1637 			&createInfoValve,                                       //  const void*							pNext;
1638 			createFlags,                                            //  VkDescriptorSetLayoutCreateFlags	flags;
1639 			static_cast<deUint32>(bindingsVec.size()),              //  deUint32							bindingCount;
1640 			de::dataOrNull(bindingsVec),                            //  const VkDescriptorSetLayoutBinding*	pBindings;
1641 		};
1642 
1643 		if (checkOnly)
1644 		{
1645 			VkDescriptorSetLayoutSupport support = initVulkanStructure();
1646 			vkd.getDescriptorSetLayoutSupport(device, &layoutCreateInfo, &support);
1647 			DescriptorSetLayoutResult result((support.supported == VK_TRUE) ? DescriptorSetLayoutResult::LayoutSupported::YES
1648 			                                                                : DescriptorSetLayoutResult::LayoutSupported::NO);
1649 			return result;
1650 		}
1651 		else
1652 		{
1653 			DescriptorSetLayoutResult result(createDescriptorSetLayout(vkd, device, &layoutCreateInfo));
1654 			return result;
1655 		}
1656 	}
1657 
1658 public:
makeDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkShaderStageFlags stageFlags,VkDescriptorSetLayoutCreateFlags createFlags) const1659 	Move<VkDescriptorSetLayout> makeDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stageFlags, VkDescriptorSetLayoutCreateFlags createFlags) const
1660 	{
1661 		return makeOrCheckDescriptorSetLayout(false /*checkOnly*/, vkd, device, stageFlags, createFlags).layout;
1662 	}
1663 
checkDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkShaderStageFlags stageFlags,VkDescriptorSetLayoutCreateFlags createFlags) const1664 	bool checkDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stageFlags, VkDescriptorSetLayoutCreateFlags createFlags) const
1665 	{
1666 		return (makeOrCheckDescriptorSetLayout(true /*checkOnly*/, vkd, device, stageFlags, createFlags).supported == DescriptorSetLayoutResult::LayoutSupported::YES);
1667 	}
1668 
numDescriptors() const1669 	size_t numDescriptors () const
1670 	{
1671 		size_t total = 0;
1672 		for (const auto& b : bindings)
1673 			total += b->size();
1674 		return total;
1675 	}
1676 
createResources(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,deUint32 qIndex,VkQueue queue,deUint32 iteration,bool useAABBs) const1677 	std::vector<Resource> createResources (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, deUint32 qIndex, VkQueue queue, deUint32 iteration, bool useAABBs) const
1678 	{
1679 		// Create resources for each binding.
1680 		std::vector<Resource> result;
1681 		result.reserve(numDescriptors());
1682 
1683 		const auto bindingsCount = static_cast<deUint32>(bindings.size());
1684 
1685 		for (deUint32 bindingIdx = 0u; bindingIdx < bindingsCount; ++bindingIdx)
1686 		{
1687 			const auto& binding             = bindings[bindingIdx];
1688 			auto        bindingResources    = binding->createResources(vkd, device, alloc, qIndex, queue, iteration, useAABBs, getDescriptorNumericValue(iteration, bindingIdx));
1689 
1690 			for (auto& resource : bindingResources)
1691 				result.emplace_back(std::move(resource));
1692 		}
1693 
1694 		return result;
1695 	}
1696 
1697 	// Updates a descriptor set with the given resources. Note: the set must have been created with a layout that's compatible with this object.
updateDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorSet set,deUint32 iteration,const std::vector<Resource> & resources) const1698 	void updateDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorSet set, deUint32 iteration, const std::vector<Resource>& resources) const
1699 	{
1700 		// Make sure the number of resources is correct.
1701 		const auto numResources = resources.size();
1702 		DE_ASSERT(numDescriptors() == numResources);
1703 
1704 		std::vector<VkWriteDescriptorSet> descriptorWrites;
1705 		descriptorWrites.reserve(numResources);
1706 
1707 		std::vector<VkDescriptorImageInfo>                          imageInfoVec;
1708 		std::vector<VkDescriptorBufferInfo>                         bufferInfoVec;
1709 		std::vector<VkBufferView>                                   bufferViewVec;
1710 		std::vector<VkWriteDescriptorSetAccelerationStructureKHR>   asWriteVec;
1711 		size_t                                                      resourceIdx = 0;
1712 
1713 		// We'll be storing pointers to elements of these vectors as we're appending elements, so we need their addresses to be stable.
1714 		imageInfoVec.reserve(numResources);
1715 		bufferInfoVec.reserve(numResources);
1716 		bufferViewVec.reserve(numResources);
1717 		asWriteVec.reserve(numResources);
1718 
1719 		for (size_t bindingIdx = 0; bindingIdx < bindings.size(); ++bindingIdx)
1720 		{
1721 			const auto& binding         = bindings[bindingIdx];
1722 			const auto  descriptorTypes = binding->typesAtIteration(iteration);
1723 
1724 			for (size_t descriptorIdx = 0; descriptorIdx < binding->size(); ++descriptorIdx)
1725 			{
1726 				// Make sure the resource type matches the expected value.
1727 				const auto& resource       = resources[resourceIdx];
1728 				const auto& descriptorType = descriptorTypes[descriptorIdx];
1729 
1730 				DE_ASSERT(resource.descriptorType == descriptorType);
1731 
1732 				// Obtain the descriptor write info for the resource.
1733 				const auto writeInfo = resource.makeWriteInfo();
1734 
1735 				switch (writeInfo.writeType)
1736 				{
1737 				case WriteType::IMAGE_INFO:                  imageInfoVec.push_back(writeInfo.imageInfo);   break;
1738 				case WriteType::BUFFER_INFO:                 bufferInfoVec.push_back(writeInfo.bufferInfo); break;
1739 				case WriteType::BUFFER_VIEW:                 bufferViewVec.push_back(writeInfo.bufferView); break;
1740 				case WriteType::ACCELERATION_STRUCTURE_INFO: asWriteVec.push_back(writeInfo.asInfo);        break;
1741 				default: DE_ASSERT(false); break;
1742 				}
1743 
1744 				// Add a new VkWriteDescriptorSet struct or extend the last one with more info. This helps us exercise different implementation code paths.
1745 				bool extended = false;
1746 
1747 				if (!descriptorWrites.empty() && descriptorIdx > 0)
1748 				{
1749 					auto& last = descriptorWrites.back();
1750 					if (last.dstSet == set /* this should always be true */ &&
1751 					    last.dstBinding == bindingIdx && (last.dstArrayElement + last.descriptorCount) == descriptorIdx &&
1752 					    last.descriptorType == descriptorType &&
1753 					    writeInfo.writeType != WriteType::ACCELERATION_STRUCTURE_INFO)
1754 					{
1755 						// The new write should be in the same vector (imageInfoVec, bufferInfoVec or bufferViewVec) so increasing the count works.
1756 						++last.descriptorCount;
1757 						extended = true;
1758 					}
1759 				}
1760 
1761 				if (!extended)
1762 				{
1763 					const VkWriteDescriptorSet write = {
1764 						VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1765 						((writeInfo.writeType == WriteType::ACCELERATION_STRUCTURE_INFO) ? &asWriteVec.back() : nullptr),
1766 						set,
1767 						static_cast<deUint32>(bindingIdx),
1768 						static_cast<deUint32>(descriptorIdx),
1769 						1u,
1770 						descriptorType,
1771 						(writeInfo.writeType == WriteType::IMAGE_INFO  ? &imageInfoVec.back()  : nullptr),
1772 						(writeInfo.writeType == WriteType::BUFFER_INFO ? &bufferInfoVec.back() : nullptr),
1773 						(writeInfo.writeType == WriteType::BUFFER_VIEW ? &bufferViewVec.back() : nullptr),
1774 					};
1775 					descriptorWrites.push_back(write);
1776 				}
1777 
1778 				++resourceIdx;
1779 			}
1780 		}
1781 
1782 		// Finally, update descriptor set with all the writes.
1783 		vkd.updateDescriptorSets(device, static_cast<deUint32>(descriptorWrites.size()), de::dataOrNull(descriptorWrites), 0u, nullptr);
1784 	}
1785 
1786 	// Copies between descriptor sets. They must be compatible and related to this set.
copyDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorSet srcSet,VkDescriptorSet dstSet) const1787 	void copyDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorSet srcSet, VkDescriptorSet dstSet) const
1788 	{
1789 		std::vector<VkCopyDescriptorSet> copies;
1790 
1791 		for (size_t bindingIdx = 0; bindingIdx < numBindings(); ++bindingIdx)
1792 		{
1793 			const auto& binding         = getBinding(bindingIdx);
1794 			const auto  bindingNumber   = static_cast<deUint32>(bindingIdx);
1795 			const auto  descriptorCount = static_cast<deUint32>(binding->size());
1796 
1797 			const VkCopyDescriptorSet copy =
1798 			{
1799 				VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,
1800 				nullptr,
1801 				// set, binding, array element.
1802 				srcSet, bindingNumber, 0u,
1803 				dstSet, bindingNumber, 0u,
1804 				descriptorCount,
1805 			};
1806 
1807 			copies.push_back(copy);
1808 		}
1809 
1810 		vkd.updateDescriptorSets(device, 0u, nullptr, static_cast<deUint32>(copies.size()), de::dataOrNull(copies));
1811 	}
1812 
1813 	// Does any binding in the set need aliasing in a given iteration?
needsAliasing(deUint32 iteration) const1814 	bool needsAliasing (deUint32 iteration) const
1815 	{
1816 		std::vector<bool> aliasingNeededFlags;
1817 		aliasingNeededFlags.reserve(bindings.size());
1818 
1819 		std::transform(begin(bindings), end(bindings), std::back_inserter(aliasingNeededFlags),
1820 		               [iteration] (const BindingInterfacePtr& b) { return b->needsAliasing(iteration); });
1821 		return std::any_of(begin(aliasingNeededFlags), end(aliasingNeededFlags), [] (bool f) { return f; });
1822 	}
1823 
1824 	// Does any binding in the set need aliasing in any iteration?
needsAnyAliasing() const1825 	bool needsAnyAliasing () const
1826 	{
1827 		const auto        numIterations       = maxTypes();
1828 		std::vector<bool> aliasingNeededFlags (numIterations, false);
1829 
1830 		for (deUint32 iteration = 0; iteration < numIterations; ++iteration)
1831 		    aliasingNeededFlags[iteration] = needsAliasing(iteration);
1832 
1833 		return std::any_of(begin(aliasingNeededFlags), end(aliasingNeededFlags), [] (bool f) { return f; });
1834 	}
1835 
1836 	// Is the last binding an unbounded array?
lastBindingIsUnbounded() const1837 	bool lastBindingIsUnbounded () const
1838 	{
1839 		if (bindings.empty())
1840 			return false;
1841 		return bindings.back()->isUnbounded();
1842 	}
1843 
1844 	// Get the variable descriptor count for the last binding if any.
getVariableDescriptorCount() const1845 	tcu::Maybe<deUint32> getVariableDescriptorCount () const
1846 	{
1847 		if (lastBindingIsUnbounded())
1848 			return tcu::just(static_cast<deUint32>(bindings.back()->size()));
1849 		return tcu::Nothing;
1850 	}
1851 
1852 	// Check if the set contains a descriptor type of the given type at the given iteration.
containsTypeAtIteration(VkDescriptorType descriptorType,deUint32 iteration) const1853 	bool containsTypeAtIteration (VkDescriptorType descriptorType, deUint32 iteration) const
1854 	{
1855 		return std::any_of(begin(bindings), end(bindings),
1856 		                   [descriptorType, iteration] (const BindingInterfacePtr& b) {
1857 			                   const auto types = b->typesAtIteration(iteration);
1858 			                   return de::contains(begin(types), end(types), descriptorType);
1859 		                   });
1860 	}
1861 
1862 	// Is any binding an array?
hasArrays() const1863 	bool hasArrays () const
1864 	{
1865 		return std::any_of(begin(bindings), end(bindings), [] (const BindingInterfacePtr& b) { return b->isArray(); });
1866 	}
1867 };
1868 
1869 enum class UpdateType
1870 {
1871 	WRITE = 0,
1872 	COPY,
1873 };
1874 
1875 enum class SourceSetType
1876 {
1877 	NORMAL = 0,
1878 	HOST_ONLY,
1879 	NO_SOURCE,
1880 };
1881 
1882 enum class UpdateMoment
1883 {
1884 	NORMAL = 0,
1885 	UPDATE_AFTER_BIND,
1886 };
1887 
1888 enum class TestingStage
1889 {
1890 	COMPUTE = 0,
1891 	VERTEX,
1892 	TESS_EVAL,
1893 	TESS_CONTROL,
1894 	GEOMETRY,
1895 	FRAGMENT,
1896 	RAY_GEN,
1897 	INTERSECTION,
1898 	ANY_HIT,
1899 	CLOSEST_HIT,
1900 	MISS,
1901 	CALLABLE,
1902 };
1903 
1904 enum class ArrayAccessType
1905 {
1906 	CONSTANT = 0,
1907 	PUSH_CONSTANT,
1908 	NO_ARRAY,
1909 };
1910 
1911 // Are we testing a ray tracing pipeline stage?
isRayTracingStage(TestingStage stage)1912 bool isRayTracingStage (TestingStage stage)
1913 {
1914 	switch (stage)
1915 	{
1916 	case TestingStage::RAY_GEN:
1917 	case TestingStage::INTERSECTION:
1918 	case TestingStage::ANY_HIT:
1919 	case TestingStage::CLOSEST_HIT:
1920 	case TestingStage::MISS:
1921 	case TestingStage::CALLABLE:
1922 		return true;
1923 	default:
1924 		break;
1925 	}
1926 
1927 	return false;
1928 }
1929 
1930 struct TestParams
1931 {
1932 	DescriptorSetPtr    descriptorSet;
1933 	UpdateType          updateType;
1934 	SourceSetStrategy   sourceSetStrategy;
1935 	SourceSetType       sourceSetType;
1936 	PoolMutableStrategy poolMutableStrategy;
1937 	UpdateMoment        updateMoment;
1938 	ArrayAccessType     arrayAccessType;
1939 	TestingStage        testingStage;
1940 
getStageFlagsvkt::BindingModel::__anon511c6de30111::TestParams1941 	VkShaderStageFlags getStageFlags () const
1942 	{
1943 		VkShaderStageFlags flags = 0u;
1944 
1945 		switch (testingStage)
1946 		{
1947 		case TestingStage::COMPUTE:			flags |= VK_SHADER_STAGE_COMPUTE_BIT;					break;
1948 		case TestingStage::VERTEX:			flags |= VK_SHADER_STAGE_VERTEX_BIT;					break;
1949 		case TestingStage::TESS_EVAL:		flags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;	break;
1950 		case TestingStage::TESS_CONTROL:	flags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;		break;
1951 		case TestingStage::GEOMETRY:		flags |= VK_SHADER_STAGE_GEOMETRY_BIT;					break;
1952 		case TestingStage::FRAGMENT:		flags |= VK_SHADER_STAGE_FRAGMENT_BIT;					break;
1953 		case TestingStage::RAY_GEN:			flags |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;				break;
1954 		case TestingStage::INTERSECTION:	flags |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;			break;
1955 		case TestingStage::ANY_HIT:			flags |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;				break;
1956 		case TestingStage::CLOSEST_HIT:		flags |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;			break;
1957 		case TestingStage::MISS:			flags |= VK_SHADER_STAGE_MISS_BIT_KHR;					break;
1958 		case TestingStage::CALLABLE:		flags |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;				break;
1959 		default:
1960 			DE_ASSERT(false);
1961 			break;
1962 		}
1963 
1964 		return flags;
1965 	}
1966 
getPipelineWriteStagevkt::BindingModel::__anon511c6de30111::TestParams1967 	VkPipelineStageFlags getPipelineWriteStage () const
1968 	{
1969 		VkPipelineStageFlags flags = 0u;
1970 
1971 		switch (testingStage)
1972 		{
1973 		case TestingStage::COMPUTE:			flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;					break;
1974 		case TestingStage::VERTEX:			flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;					break;
1975 		case TestingStage::TESS_EVAL:		flags |= VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;	break;
1976 		case TestingStage::TESS_CONTROL:	flags |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;		break;
1977 		case TestingStage::GEOMETRY:		flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;					break;
1978 		case TestingStage::FRAGMENT:		flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;					break;
1979 		case TestingStage::RAY_GEN:			// fallthrough
1980 		case TestingStage::INTERSECTION:	// fallthrough
1981 		case TestingStage::ANY_HIT:			// fallthrough
1982 		case TestingStage::CLOSEST_HIT:		// fallthrough
1983 		case TestingStage::MISS:			// fallthrough
1984 		case TestingStage::CALLABLE:		flags |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;			break;
1985 		default:
1986 			DE_ASSERT(false);
1987 			break;
1988 		}
1989 
1990 		return flags;
1991 	}
1992 
1993 private:
getLayoutCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams1994 	VkDescriptorSetLayoutCreateFlags getLayoutCreateFlags (bool isSourceSet) const
1995 	{
1996 		// UPDATE_AFTER_BIND cannot be used with HOST_ONLY sets.
1997 		//DE_ASSERT(!(updateMoment == UpdateMoment::UPDATE_AFTER_BIND && sourceSetType == SourceSetType::HOST_ONLY));
1998 
1999 		VkDescriptorSetLayoutCreateFlags createFlags = 0u;
2000 
2001 		if ((!isSourceSet || sourceSetType != SourceSetType::HOST_ONLY) && updateMoment == UpdateMoment::UPDATE_AFTER_BIND)
2002 			createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT;
2003 
2004 		if (isSourceSet && sourceSetType == SourceSetType::HOST_ONLY)
2005 			createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE;
2006 
2007 		return createFlags;
2008 	}
2009 
2010 public:
getSrcLayoutCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams2011 	VkDescriptorSetLayoutCreateFlags getSrcLayoutCreateFlags () const
2012 	{
2013 		return getLayoutCreateFlags(true);
2014 	}
2015 
getDstLayoutCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams2016 	VkDescriptorSetLayoutCreateFlags getDstLayoutCreateFlags () const
2017 	{
2018 		return getLayoutCreateFlags(false);
2019 	}
2020 
2021 private:
getPoolCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams2022 	VkDescriptorPoolCreateFlags getPoolCreateFlags (bool isSourceSet) const
2023 	{
2024 		// UPDATE_AFTER_BIND cannot be used with HOST_ONLY sets.
2025 		//DE_ASSERT(!(updateMoment == UpdateMoment::UPDATE_AFTER_BIND && sourceSetType == SourceSetType::HOST_ONLY));
2026 
2027 		VkDescriptorPoolCreateFlags poolCreateFlags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
2028 
2029 		if ((!isSourceSet || sourceSetType != SourceSetType::HOST_ONLY) && updateMoment == UpdateMoment::UPDATE_AFTER_BIND)
2030 			poolCreateFlags |= VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT;
2031 
2032 		if (isSourceSet && sourceSetType == SourceSetType::HOST_ONLY)
2033 			poolCreateFlags |= VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE;
2034 
2035 		return poolCreateFlags;
2036 	}
2037 
2038 public:
getSrcPoolCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams2039 	VkDescriptorPoolCreateFlags getSrcPoolCreateFlags () const
2040 	{
2041 		return getPoolCreateFlags(true);
2042 	}
2043 
getDstPoolCreateFlagsvkt::BindingModel::__anon511c6de30111::TestParams2044 	VkDescriptorPoolCreateFlags getDstPoolCreateFlags () const
2045 	{
2046 		return getPoolCreateFlags(false);
2047 	}
2048 
getBindPointvkt::BindingModel::__anon511c6de30111::TestParams2049 	VkPipelineBindPoint getBindPoint () const
2050 	{
2051 		if (testingStage == TestingStage::COMPUTE)
2052 			return VK_PIPELINE_BIND_POINT_COMPUTE;
2053 		if (isRayTracingStage(testingStage))
2054 			return VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
2055 		return VK_PIPELINE_BIND_POINT_GRAPHICS;
2056 	}
2057 };
2058 
2059 class MutableTypesTest : public TestCase
2060 {
2061 public:
MutableTypesTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)2062 	MutableTypesTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
2063 		: TestCase(testCtx, name, description)
2064 		, m_params(params)
2065 	{}
2066 
2067 	~MutableTypesTest () override = default;
2068 
2069 	void            initPrograms        (vk::SourceCollections& programCollection) const override;
2070 	TestInstance*   createInstance      (Context& context) const override;
2071 	void            checkSupport        (Context& context) const override;
2072 
2073 private:
2074 	TestParams      m_params;
2075 };
2076 
2077 class MutableTypesInstance : public TestInstance
2078 {
2079 public:
MutableTypesInstance(Context & context,const TestParams & params)2080 	MutableTypesInstance (Context& context, const TestParams& params)
2081 		: TestInstance  (context)
2082 		, m_params      (params)
2083 	{}
2084 
2085 	~MutableTypesInstance () override = default;
2086 
2087 	tcu::TestStatus iterate () override;
2088 
2089 private:
2090 	TestParams      m_params;
2091 };
2092 
2093 // Check if a descriptor set contains a given descriptor type in any iteration up to maxTypes().
containsAnyDescriptorType(const DescriptorSet & descriptorSet,VkDescriptorType descriptorType)2094 bool containsAnyDescriptorType (const DescriptorSet& descriptorSet, VkDescriptorType descriptorType)
2095 {
2096 	const auto numIterations = descriptorSet.maxTypes();
2097 
2098 	for (deUint32 iter = 0u; iter < numIterations; ++iter)
2099 	{
2100 		if (descriptorSet.containsTypeAtIteration(descriptorType, iter))
2101 			return true;
2102 	}
2103 
2104 	return false;
2105 }
2106 
2107 // Check if testing this descriptor set needs an external image (for sampler descriptors).
needsExternalImage(const DescriptorSet & descriptorSet)2108 bool needsExternalImage (const DescriptorSet& descriptorSet)
2109 {
2110 	return containsAnyDescriptorType(descriptorSet, VK_DESCRIPTOR_TYPE_SAMPLER);
2111 }
2112 
2113 // Check if testing this descriptor set needs an external sampler (for sampled images).
needsExternalSampler(const DescriptorSet & descriptorSet)2114 bool needsExternalSampler (const DescriptorSet& descriptorSet)
2115 {
2116 	return containsAnyDescriptorType(descriptorSet, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
2117 }
2118 
2119 // Check if this descriptor set contains a input attachments.
usesInputAttachments(const DescriptorSet & descriptorSet)2120 bool usesInputAttachments (const DescriptorSet& descriptorSet)
2121 {
2122 	return containsAnyDescriptorType(descriptorSet, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
2123 }
2124 
2125 // Check if this descriptor set contains acceleration structures.
usesAccelerationStructures(const DescriptorSet & descriptorSet)2126 bool usesAccelerationStructures (const DescriptorSet& descriptorSet)
2127 {
2128 	return containsAnyDescriptorType(descriptorSet, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
2129 }
2130 
shaderName(deUint32 iteration)2131 std::string shaderName (deUint32 iteration)
2132 {
2133 	return ("iteration-" + de::toString(iteration));
2134 }
2135 
initPrograms(vk::SourceCollections & programCollection) const2136 void MutableTypesTest::initPrograms (vk::SourceCollections& programCollection) const
2137 {
2138 	const bool						usePushConstants      = (m_params.arrayAccessType == ArrayAccessType::PUSH_CONSTANT);
2139 	const bool						useExternalImage      = needsExternalImage(*m_params.descriptorSet);
2140 	const bool						useExternalSampler    = needsExternalSampler(*m_params.descriptorSet);
2141 	const bool						rayQueries            = usesAccelerationStructures(*m_params.descriptorSet);
2142 	const bool						rayTracing            = isRayTracingStage(m_params.testingStage);
2143 	const auto						numIterations         = m_params.descriptorSet->maxTypes();
2144 	const auto						numBindings           = m_params.descriptorSet->numBindings();
2145 	const vk::ShaderBuildOptions	rtBuildOptions        (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
2146 
2147 	// Extra set and bindings for external resources.
2148 	std::ostringstream extraSet;
2149 	deUint32           extraBindings = 0u;
2150 
2151 	extraSet << "layout (set=1, binding=" << extraBindings++ << ") buffer OutputBufferBlock { uint value[" << numIterations << "]; } outputBuffer;\n";
2152 	if (useExternalImage)
2153 		extraSet << "layout (set=1, binding=" << extraBindings++ << ") uniform utexture2D externalSampledImage;\n";
2154 	if (useExternalSampler)
2155 		extraSet << "layout (set=1, binding=" << extraBindings++ << ") uniform sampler externalSampler;\n";
2156 	// The extra binding below will be declared in the "passthrough" ray generation shader.
2157 #if 0
2158 	if (rayTracing)
2159 		extraSet << "layout (set=1, binding=" << extraBindings++ << ") uniform accelerationStructureEXT externalAS;\n";
2160 #endif
2161 
2162 	// Common vertex preamble.
2163 	std::ostringstream vertexPreamble;
2164 	vertexPreamble
2165 			<< "vec2 vertexPositions[3] = vec2[](\n"
2166 			<< "  vec2(0.0, -0.5),\n"
2167 			<< "  vec2(0.5, 0.5),\n"
2168 			<< "  vec2(-0.5, 0.5)\n"
2169 			<< ");\n"
2170 			;
2171 
2172 	// Vertex shader body common statements.
2173 	std::ostringstream vertexBodyCommon;
2174 	vertexBodyCommon << "  gl_Position = vec4(vertexPositions[gl_VertexIndex], 0.0, 1.0);\n";
2175 
2176 	// Common tessellation control preamble.
2177 	std::ostringstream tescPreamble;
2178 	tescPreamble
2179 		<< "layout (vertices=3) out;\n"
2180 		<< "in gl_PerVertex\n"
2181 		<< "{\n"
2182 		<< "  vec4 gl_Position;\n"
2183 		<< "} gl_in[gl_MaxPatchVertices];\n"
2184 		<< "out gl_PerVertex\n"
2185 		<< "{\n"
2186 		<< "  vec4 gl_Position;\n"
2187 		<< "} gl_out[];\n"
2188 		;
2189 
2190 	// Common tessellation control body.
2191 	std::ostringstream tescBodyCommon;
2192 	tescBodyCommon
2193 		<< "  gl_TessLevelInner[0] = 1.0;\n"
2194 		<< "  gl_TessLevelInner[1] = 1.0;\n"
2195 		<< "  gl_TessLevelOuter[0] = 1.0;\n"
2196 		<< "  gl_TessLevelOuter[1] = 1.0;\n"
2197 		<< "  gl_TessLevelOuter[2] = 1.0;\n"
2198 		<< "  gl_TessLevelOuter[3] = 1.0;\n"
2199 		<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2200 		;
2201 
2202 	// Common tessellation evaluation preamble.
2203 	std::ostringstream tesePreamble;
2204 	tesePreamble
2205 		<< "layout (triangles, fractional_odd_spacing, cw) in;\n"
2206 		<< "in gl_PerVertex\n"
2207 		<< "{\n"
2208 		<< "  vec4 gl_Position;\n"
2209 		<< "} gl_in[gl_MaxPatchVertices];\n"
2210 		<< "out gl_PerVertex\n"
2211 		<< "{\n"
2212 		<< "  vec4 gl_Position;\n"
2213 		<< "};\n"
2214 		;
2215 
2216 	// Common tessellation evaluation body.
2217 	std::ostringstream teseBodyCommon;
2218 	teseBodyCommon
2219 		<< "  gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
2220 		<< "                (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
2221 		<< "                (gl_TessCoord.z * gl_in[2].gl_Position);\n"
2222 		;
2223 
2224 	// Shader preamble.
2225 	std::ostringstream preamble;
2226 
2227 	preamble
2228 		<< "#version 460\n"
2229 		<< "#extension GL_EXT_nonuniform_qualifier : enable\n"
2230 		<< "#extension GL_EXT_debug_printf : enable\n"
2231 		<< (rayTracing ? "#extension GL_EXT_ray_tracing : enable\n" : "")
2232 		<< (rayQueries ? "#extension GL_EXT_ray_query : enable\n" : "")
2233 		<< "\n"
2234 		;
2235 
2236 	if (m_params.testingStage == TestingStage::VERTEX)
2237 	{
2238 		preamble << vertexPreamble.str();
2239 	}
2240 	else if (m_params.testingStage == TestingStage::COMPUTE)
2241 	{
2242 		preamble
2243 			<< "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
2244 			<< "\n"
2245 			;
2246 	}
2247 	else if (m_params.testingStage == TestingStage::GEOMETRY)
2248 	{
2249 		preamble
2250 			<< "layout (triangles) in;\n"
2251 			<< "layout (triangle_strip, max_vertices=3) out;\n"
2252 			<< "in gl_PerVertex\n"
2253 			<< "{\n"
2254 			<< "  vec4 gl_Position;\n"
2255 			<< "} gl_in[3];\n"
2256 			<< "out gl_PerVertex\n"
2257 			<< "{\n"
2258 			<< "  vec4 gl_Position;\n"
2259 			<< "};\n"
2260 			;
2261 	}
2262 	else if (m_params.testingStage == TestingStage::TESS_CONTROL)
2263 	{
2264 		preamble << tescPreamble.str();
2265 	}
2266 	else if (m_params.testingStage == TestingStage::TESS_EVAL)
2267 	{
2268 		preamble << tesePreamble.str();
2269 	}
2270 	else if (m_params.testingStage == TestingStage::CALLABLE)
2271 	{
2272 		preamble << "layout (location=0) callableDataInEXT float unusedCallableData;\n";
2273 	}
2274 	else if (m_params.testingStage == TestingStage::CLOSEST_HIT ||
2275 			 m_params.testingStage == TestingStage::ANY_HIT ||
2276 			 m_params.testingStage == TestingStage::MISS)
2277 	{
2278 		preamble << "layout (location=0) rayPayloadInEXT float unusedRayPayload;\n";
2279 	}
2280 	else if (m_params.testingStage == TestingStage::INTERSECTION)
2281 	{
2282 		preamble << "hitAttributeEXT vec3 hitAttribute;\n";
2283 	}
2284 
2285 	preamble << extraSet.str();
2286 	if (usePushConstants)
2287 		preamble << "layout (push_constant, std430) uniform PushConstantBlock { uint zero; } pc;\n";
2288 	preamble << "\n";
2289 
2290 	// We need to create a shader per iteration.
2291 	for (deUint32 iter = 0u; iter < numIterations; ++iter)
2292 	{
2293 		// Shader preamble.
2294 		std::ostringstream shader;
2295 		shader << preamble.str();
2296 
2297 		deUint32 inputAttachmentCount = 0u;
2298 
2299 		// Descriptor declarations for this iteration.
2300 		for (size_t bindingIdx = 0; bindingIdx < numBindings; ++bindingIdx)
2301 		{
2302 			DE_ASSERT(bindingIdx <= std::numeric_limits<deUint32>::max());
2303 
2304 			const auto binding            = m_params.descriptorSet->getBinding(bindingIdx);
2305 			const auto bindingTypes       = binding->typesAtIteration(iter);
2306 			const auto hasInputAttachment = de::contains(begin(bindingTypes), end(bindingTypes), VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
2307 			const auto isArray            = binding->isArray();
2308 			const auto isUnbounded        = binding->isUnbounded();
2309 			const auto bindingSize        = binding->size();
2310 
2311 			// If the binding is an input attachment, make sure it's not an array.
2312 			DE_ASSERT(!hasInputAttachment || !isArray);
2313 
2314 			// Make sure the descriptor count fits a deInt32 if needed.
2315 			DE_ASSERT(!isArray || isUnbounded || bindingSize <= static_cast<size_t>(std::numeric_limits<deInt32>::max()));
2316 
2317 			const auto arraySize = (isArray ? (isUnbounded ? tcu::just(deInt32{-1}) : tcu::just(static_cast<deInt32>(bindingSize)))
2318 			                                : tcu::Nothing);
2319 
2320 			shader << binding->glslDeclarations(iter, 0u, static_cast<deUint32>(bindingIdx), inputAttachmentCount, arraySize);
2321 
2322 			if (hasInputAttachment)
2323 				++inputAttachmentCount;
2324 		}
2325 
2326 		// Main body.
2327 		shader
2328 			<< "\n"
2329 			<< "void main() {\n"
2330 			// This checks if we are the first invocation to arrive here, so the checks are executed only once.
2331 			<< "  const uint flag = atomicCompSwap(outputBuffer.value[" << iter << "], 0u, 1u);\n"
2332 			<< "  if (flag == 0u) {\n"
2333 			<< "    uint anyError = 0u;\n"
2334 			;
2335 
2336 		for (size_t bindingIdx = 0; bindingIdx < numBindings; ++bindingIdx)
2337 		{
2338 			const auto binding = m_params.descriptorSet->getBinding(bindingIdx);
2339 			const auto idx32 = static_cast<deUint32>(bindingIdx);
2340 			shader << binding->glslCheckStatements(iter, 0u, idx32, getDescriptorNumericValue(iter, idx32), tcu::Nothing, usePushConstants);
2341 		}
2342 
2343 		shader
2344 			<< "    if (anyError == 0u) {\n"
2345 			<< "      atomicAdd(outputBuffer.value[" << iter << "], 1u);\n"
2346 			<< "    }\n"
2347 			<< "  }\n" // Closes if (flag == 0u).
2348 			;
2349 
2350 		if (m_params.testingStage == TestingStage::VERTEX)
2351 		{
2352 			shader << vertexBodyCommon.str();
2353 		}
2354 		else if (m_params.testingStage == TestingStage::GEOMETRY)
2355 		{
2356 			shader
2357 				<< "  gl_Position = gl_in[0].gl_Position; EmitVertex();\n"
2358 				<< "  gl_Position = gl_in[1].gl_Position; EmitVertex();\n"
2359 				<< "  gl_Position = gl_in[2].gl_Position; EmitVertex();\n"
2360 				;
2361 		}
2362 		else if (m_params.testingStage == TestingStage::TESS_CONTROL)
2363 		{
2364 			shader << tescBodyCommon.str();
2365 		}
2366 		else if (m_params.testingStage == TestingStage::TESS_EVAL)
2367 		{
2368 			shader << teseBodyCommon.str();
2369 		}
2370 
2371 		shader
2372 			<< "}\n" // End of main().
2373 			;
2374 
2375 		{
2376 			const auto	shaderNameStr	= shaderName(iter);
2377 			const auto	shaderStr		= shader.str();
2378 			auto&		glslSource		= programCollection.glslSources.add(shaderNameStr);
2379 
2380 			if (m_params.testingStage == TestingStage::COMPUTE)
2381 				glslSource << glu::ComputeSource(shaderStr);
2382 			else if (m_params.testingStage == TestingStage::VERTEX)
2383 				glslSource << glu::VertexSource(shaderStr);
2384 			else if (m_params.testingStage == TestingStage::FRAGMENT)
2385 				glslSource << glu::FragmentSource(shaderStr);
2386 			else if (m_params.testingStage == TestingStage::GEOMETRY)
2387 				glslSource << glu::GeometrySource(shaderStr);
2388 			else if (m_params.testingStage == TestingStage::TESS_CONTROL)
2389 				glslSource << glu::TessellationControlSource(shaderStr);
2390 			else if (m_params.testingStage == TestingStage::TESS_EVAL)
2391 				glslSource << glu::TessellationEvaluationSource(shaderStr);
2392 			else if (m_params.testingStage == TestingStage::RAY_GEN)
2393 				glslSource << glu::RaygenSource(updateRayTracingGLSL(shaderStr));
2394 			else if (m_params.testingStage == TestingStage::INTERSECTION)
2395 				glslSource << glu::IntersectionSource(updateRayTracingGLSL(shaderStr));
2396 			else if (m_params.testingStage == TestingStage::ANY_HIT)
2397 				glslSource << glu::AnyHitSource(updateRayTracingGLSL(shaderStr));
2398 			else if (m_params.testingStage == TestingStage::CLOSEST_HIT)
2399 				glslSource << glu::ClosestHitSource(updateRayTracingGLSL(shaderStr));
2400 			else if (m_params.testingStage == TestingStage::MISS)
2401 				glslSource << glu::MissSource(updateRayTracingGLSL(shaderStr));
2402 			else if (m_params.testingStage == TestingStage::CALLABLE)
2403 				glslSource << glu::CallableSource(updateRayTracingGLSL(shaderStr));
2404 			else
2405 				DE_ASSERT(false);
2406 
2407 			if (rayTracing || rayQueries)
2408 				glslSource << rtBuildOptions;
2409 		}
2410 	}
2411 
2412 	if (m_params.testingStage == TestingStage::FRAGMENT
2413 		|| m_params.testingStage == TestingStage::GEOMETRY
2414 		|| m_params.testingStage == TestingStage::TESS_CONTROL
2415 		|| m_params.testingStage == TestingStage::TESS_EVAL)
2416 	{
2417 		// Add passthrough vertex shader that works for points.
2418 		std::ostringstream vertPassthrough;
2419 		vertPassthrough
2420 			<< "#version 460\n"
2421 			<< "out gl_PerVertex\n"
2422 			<< "{\n"
2423 			<< "  vec4 gl_Position;\n"
2424 			<< "};\n"
2425 			<< vertexPreamble.str()
2426 			<< "void main() {\n"
2427 			<< vertexBodyCommon.str()
2428 			<< "}\n"
2429 			;
2430 		programCollection.glslSources.add("vert") << glu::VertexSource(vertPassthrough.str());
2431 	}
2432 
2433 	if (m_params.testingStage == TestingStage::TESS_CONTROL)
2434 	{
2435 		// Add passthrough tessellation evaluation shader.
2436 		std::ostringstream tesePassthrough;
2437 		tesePassthrough
2438 			<< "#version 460\n"
2439 			<< tesePreamble.str()
2440 			<< "void main (void)\n"
2441 			<< "{\n"
2442 			<< teseBodyCommon.str()
2443 			<< "}\n"
2444 			;
2445 
2446 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tesePassthrough.str());
2447 	}
2448 
2449 	if (m_params.testingStage == TestingStage::TESS_EVAL)
2450 	{
2451 		// Add passthrough tessellation control shader.
2452 		std::ostringstream tescPassthrough;
2453 		tescPassthrough
2454 			<< "#version 460\n"
2455 			<< tescPreamble.str()
2456 			<< "void main (void)\n"
2457 			<< "{\n"
2458 			<< tescBodyCommon.str()
2459 			<< "}\n"
2460 			;
2461 
2462 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescPassthrough.str());
2463 	}
2464 
2465 	if (rayTracing && m_params.testingStage != TestingStage::RAY_GEN)
2466 	{
2467 		// Add a "passthrough" ray generation shader.
2468 		std::ostringstream rgen;
2469 		rgen
2470 			<< "#version 460 core\n"
2471 			<< "#extension GL_EXT_ray_tracing : require\n"
2472 			<< "layout (set=1, binding=" << extraBindings << ") uniform accelerationStructureEXT externalAS;\n"
2473 			<< ((m_params.testingStage == TestingStage::CALLABLE)
2474 				? "layout (location=0) callableDataEXT float unusedCallableData;\n"
2475 				: "layout (location=0) rayPayloadEXT float unusedRayPayload;\n")
2476 			<< "\n"
2477 			<< "void main()\n"
2478 			<< "{\n"
2479 			;
2480 
2481 		if (m_params.testingStage == TestingStage::INTERSECTION
2482 			|| m_params.testingStage == TestingStage::ANY_HIT
2483 			|| m_params.testingStage == TestingStage::CLOSEST_HIT
2484 			|| m_params.testingStage == TestingStage::MISS)
2485 		{
2486 			// We need to trace rays in this case to get hits or misses.
2487 			const auto zDir = ((m_params.testingStage == TestingStage::MISS) ? "-1.0" : "1.0");
2488 
2489 			rgen
2490 				<< "  const uint cullMask = 0xFF;\n"
2491 				<< "  const float tMin = 1.0;\n"
2492 				<< "  const float tMax = 10.0;\n"
2493 				<< "  const vec3 origin = vec3(0.0, 0.0, 0.0);\n"
2494 				<< "  const vec3 direction = vec3(0.0, 0.0, " << zDir << ");\n"
2495 				<< "  traceRayEXT(externalAS, gl_RayFlagsNoneEXT, cullMask, 0, 0, 0, origin, tMin, direction, tMax, 0);\n"
2496 				;
2497 
2498 		}
2499 		else if (m_params.testingStage == TestingStage::CALLABLE)
2500 		{
2501 			rgen << "  executeCallableEXT(0, 0);\n";
2502 		}
2503 
2504 		// End of main().
2505 		rgen << "}\n";
2506 
2507 		programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << rtBuildOptions;
2508 
2509 		// Intersection shaders will ignore the intersection, so we need a passthrough miss shader.
2510 		if (m_params.testingStage == TestingStage::INTERSECTION)
2511 		{
2512 			std::ostringstream miss;
2513 			miss
2514 				<< "#version 460 core\n"
2515 				<< "#extension GL_EXT_ray_tracing : require\n"
2516 				<< "layout (location=0) rayPayloadEXT float unusedRayPayload;\n"
2517 				<< "\n"
2518 				<< "void main()\n"
2519 				<< "{\n"
2520 				<< "}\n"
2521 				;
2522 
2523 			programCollection.glslSources.add("miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << rtBuildOptions;
2524 		}
2525 	}
2526 }
2527 
createInstance(Context & context) const2528 TestInstance* MutableTypesTest::createInstance (Context& context) const
2529 {
2530 	return new MutableTypesInstance(context, m_params);
2531 }
2532 
requirePartiallyBound(Context & context)2533 void requirePartiallyBound (Context& context)
2534 {
2535 	context.requireDeviceFunctionality("VK_EXT_descriptor_indexing");
2536 	const auto& indexingFeatures = context.getDescriptorIndexingFeatures();
2537 	if (!indexingFeatures.descriptorBindingPartiallyBound)
2538 		TCU_THROW(NotSupportedError, "Partially bound bindings not supported");
2539 }
2540 
requireVariableDescriptorCount(Context & context)2541 void requireVariableDescriptorCount (Context& context)
2542 {
2543 	context.requireDeviceFunctionality("VK_EXT_descriptor_indexing");
2544 	const auto& indexingFeatures = context.getDescriptorIndexingFeatures();
2545 	if (!indexingFeatures.descriptorBindingVariableDescriptorCount)
2546 		TCU_THROW(NotSupportedError, "Variable descriptor count not supported");
2547 }
2548 
2549 // Calculates the set of used descriptor types for a given set and iteration count, for bindings matching a predicate.
getUsedDescriptorTypes(const DescriptorSet & descriptorSet,deUint32 numIterations,bool (* predicate)(const BindingInterface * binding))2550 std::set<VkDescriptorType> getUsedDescriptorTypes (const DescriptorSet& descriptorSet, deUint32 numIterations, bool (*predicate)(const BindingInterface* binding))
2551 {
2552 	std::set<VkDescriptorType> usedDescriptorTypes;
2553 
2554 	for (size_t bindingIdx = 0; bindingIdx < descriptorSet.numBindings(); ++bindingIdx)
2555 	{
2556 		const auto bindingPtr = descriptorSet.getBinding(bindingIdx);
2557 		if (predicate(bindingPtr))
2558 		{
2559 			for (deUint32 iter = 0u; iter < numIterations; ++iter)
2560 			{
2561 				const auto descTypes = bindingPtr->typesAtIteration(iter);
2562 				usedDescriptorTypes.insert(begin(descTypes), end(descTypes));
2563 			}
2564 		}
2565 	}
2566 
2567 	return usedDescriptorTypes;
2568 }
2569 
getAllUsedDescriptorTypes(const DescriptorSet & descriptorSet,deUint32 numIterations)2570 std::set<VkDescriptorType> getAllUsedDescriptorTypes (const DescriptorSet& descriptorSet, deUint32 numIterations)
2571 {
2572 	return getUsedDescriptorTypes(descriptorSet, numIterations, [] (const BindingInterface*) { return true; });
2573 }
2574 
getUsedArrayDescriptorTypes(const DescriptorSet & descriptorSet,deUint32 numIterations)2575 std::set<VkDescriptorType> getUsedArrayDescriptorTypes (const DescriptorSet& descriptorSet, deUint32 numIterations)
2576 {
2577 	return getUsedDescriptorTypes(descriptorSet, numIterations, [] (const BindingInterface* b) { return b->isArray(); });
2578 }
2579 
2580 // Are we testing a vertex pipeline stage?
isVertexStage(TestingStage stage)2581 bool isVertexStage (TestingStage stage)
2582 {
2583 	switch (stage)
2584 	{
2585 	case TestingStage::VERTEX:
2586 	case TestingStage::TESS_CONTROL:
2587 	case TestingStage::TESS_EVAL:
2588 	case TestingStage::GEOMETRY:
2589 		return true;
2590 	default:
2591 		break;
2592 	}
2593 
2594 	return false;
2595 }
2596 
checkSupport(Context & context) const2597 void MutableTypesTest::checkSupport (Context& context) const
2598 {
2599 	context.requireDeviceFunctionality("VK_VALVE_mutable_descriptor_type");
2600 
2601 	// Check ray tracing if needed.
2602 	const bool rayTracing = isRayTracingStage(m_params.testingStage);
2603 
2604 	if (rayTracing)
2605 	{
2606 		context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2607 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
2608 	}
2609 
2610 	// Check if ray queries are needed. Ray queries are used to verify acceleration structure descriptors.
2611 	const bool rayQueriesNeeded = usesAccelerationStructures(*m_params.descriptorSet);
2612 	if (rayQueriesNeeded)
2613 	{
2614 		context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2615 		context.requireDeviceFunctionality("VK_KHR_ray_query");
2616 	}
2617 
2618 	// We'll use iterations to check each mutable type, as needed.
2619 	const auto numIterations = m_params.descriptorSet->maxTypes();
2620 
2621 	if (m_params.descriptorSet->lastBindingIsUnbounded())
2622 		requireVariableDescriptorCount(context);
2623 
2624 	for (deUint32 iter = 0u; iter < numIterations; ++iter)
2625 	{
2626 		if (m_params.descriptorSet->needsAliasing(iter))
2627 		{
2628 			requirePartiallyBound(context);
2629 			break;
2630 		}
2631 	}
2632 
2633 	if (m_params.updateMoment == UpdateMoment::UPDATE_AFTER_BIND)
2634 	{
2635 		// Check update after bind for each used descriptor type.
2636 		const auto& usedDescriptorTypes = getAllUsedDescriptorTypes(*m_params.descriptorSet, numIterations);
2637 		const auto& indexingFeatures    = context.getDescriptorIndexingFeatures();
2638 
2639 		for (const auto& descType : usedDescriptorTypes)
2640 		{
2641 			switch (descType)
2642 			{
2643 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2644 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2645 				if (!indexingFeatures.descriptorBindingUniformBufferUpdateAfterBind)
2646 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for uniform buffers");
2647 				break;
2648 
2649 			case VK_DESCRIPTOR_TYPE_SAMPLER:
2650 			case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2651 			case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2652 				if (!indexingFeatures.descriptorBindingSampledImageUpdateAfterBind)
2653 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for samplers and sampled images");
2654 				break;
2655 
2656 			case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2657 				if (!indexingFeatures.descriptorBindingStorageImageUpdateAfterBind)
2658 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for storage images");
2659 				break;
2660 
2661 			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2662 			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
2663 				if (!indexingFeatures.descriptorBindingStorageBufferUpdateAfterBind)
2664 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for storage buffers");
2665 				break;
2666 
2667 			case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2668 				if (!indexingFeatures.descriptorBindingUniformTexelBufferUpdateAfterBind)
2669 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for uniform texel buffers");
2670 				break;
2671 
2672 			case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2673 				if (!indexingFeatures.descriptorBindingStorageTexelBufferUpdateAfterBind)
2674 					TCU_THROW(NotSupportedError, "Update-after-bind not supported for storage texel buffers");
2675 				break;
2676 
2677 			case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2678 				TCU_THROW(InternalError, "Tests do not support update-after-bind with input attachments");
2679 
2680 			case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT:
2681 				{
2682 					// Just in case we ever mix some of these in.
2683 					context.requireDeviceFunctionality("VK_EXT_inline_uniform_block");
2684 					const auto& iubFeatures = context.getInlineUniformBlockFeaturesEXT();
2685 					if (!iubFeatures.descriptorBindingInlineUniformBlockUpdateAfterBind)
2686 						TCU_THROW(NotSupportedError, "Update-after-bind not supported for inline uniform blocks");
2687 				}
2688 				break;
2689 
2690 			case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
2691 				{
2692 					// Just in case we ever mix some of these in.
2693 					context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2694 					const auto& asFeatures = context.getAccelerationStructureFeatures();
2695 					if (!asFeatures.descriptorBindingAccelerationStructureUpdateAfterBind)
2696 						TCU_THROW(NotSupportedError, "Update-after-bind not supported for acceleration structures");
2697 				}
2698 				break;
2699 
2700 			case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE:
2701 				TCU_THROW(InternalError, "Found VK_DESCRIPTOR_TYPE_MUTABLE_VALVE in list of used descriptor types");
2702 
2703 			default:
2704 				TCU_THROW(InternalError, "Unexpected descriptor type found in list of used descriptor types: " + de::toString(descType));
2705 			}
2706 		}
2707 	}
2708 
2709 	if (m_params.arrayAccessType == ArrayAccessType::PUSH_CONSTANT)
2710 	{
2711 		// These require dynamically uniform indices.
2712 		const auto& usedDescriptorTypes         = getUsedArrayDescriptorTypes(*m_params.descriptorSet, numIterations);
2713 		const auto& features                    = context.getDeviceFeatures();
2714 		const auto descriptorIndexingSupported  = context.isDeviceFunctionalitySupported("VK_EXT_descriptor_indexing");
2715 		const auto& indexingFeatures            = context.getDescriptorIndexingFeatures();
2716 
2717 		for (const auto& descType : usedDescriptorTypes)
2718 		{
2719 			switch (descType)
2720 			{
2721 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
2722 			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
2723 				if (!features.shaderUniformBufferArrayDynamicIndexing)
2724 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for uniform buffers");
2725 				break;
2726 
2727 			case VK_DESCRIPTOR_TYPE_SAMPLER:
2728 			case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
2729 			case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
2730 				if (!features.shaderSampledImageArrayDynamicIndexing)
2731 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for samplers and sampled images");
2732 				break;
2733 
2734 			case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
2735 				if (!features.shaderStorageImageArrayDynamicIndexing)
2736 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for storage images");
2737 				break;
2738 
2739 			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
2740 			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
2741 				if (!features.shaderStorageBufferArrayDynamicIndexing)
2742 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for storage buffers");
2743 				break;
2744 
2745 			case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
2746 				if (!descriptorIndexingSupported || !indexingFeatures.shaderUniformTexelBufferArrayDynamicIndexing)
2747 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for uniform texel buffers");
2748 				break;
2749 
2750 			case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
2751 				if (!descriptorIndexingSupported || !indexingFeatures.shaderStorageTexelBufferArrayDynamicIndexing)
2752 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for storage texel buffers");
2753 				break;
2754 
2755 			case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
2756 				if (!descriptorIndexingSupported || !indexingFeatures.shaderInputAttachmentArrayDynamicIndexing)
2757 					TCU_THROW(NotSupportedError, "Dynamic indexing not supported for input attachments");
2758 				break;
2759 
2760 			case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
2761 				context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
2762 				break;
2763 
2764 			case VK_DESCRIPTOR_TYPE_MUTABLE_VALVE:
2765 				TCU_THROW(InternalError, "Found VK_DESCRIPTOR_TYPE_MUTABLE_VALVE in list of used array descriptor types");
2766 
2767 			default:
2768 				TCU_THROW(InternalError, "Unexpected descriptor type found in list of used descriptor types: " + de::toString(descType));
2769 			}
2770 		}
2771 	}
2772 
2773 	// Check layout support.
2774 	{
2775 		const auto& vkd               = context.getDeviceInterface();
2776 		const auto  device            = context.getDevice();
2777 		const auto  stageFlags        = m_params.getStageFlags();
2778 
2779 		{
2780 			const auto  layoutCreateFlags = m_params.getDstLayoutCreateFlags();
2781 			const auto  supported         = m_params.descriptorSet->checkDescriptorSetLayout(vkd, device, stageFlags, layoutCreateFlags);
2782 
2783 			if (!supported)
2784 				TCU_THROW(NotSupportedError, "Required descriptor set layout not supported");
2785 		}
2786 
2787 		if (m_params.updateType == UpdateType::COPY)
2788 		{
2789 			const auto  layoutCreateFlags = m_params.getSrcLayoutCreateFlags();
2790 			const auto  supported         = m_params.descriptorSet->checkDescriptorSetLayout(vkd, device, stageFlags, layoutCreateFlags);
2791 
2792 			if (!supported)
2793 				TCU_THROW(NotSupportedError, "Required descriptor set layout for source set not supported");
2794 
2795 			// Check specific layouts for the different source sets are supported.
2796 			for (deUint32 iter = 0u; iter < numIterations; ++iter)
2797 			{
2798 				const auto srcSet             = m_params.descriptorSet->genSourceSet(m_params.sourceSetStrategy, iter);
2799 				const auto srcLayoutSupported = srcSet->checkDescriptorSetLayout(vkd, device, stageFlags, layoutCreateFlags);
2800 
2801 				if (!srcLayoutSupported)
2802 					TCU_THROW(NotSupportedError, "Descriptor set layout for source set at iteration " + de::toString(iter) + " not supported");
2803 			}
2804 		}
2805 	}
2806 
2807 	// Check supported stores and stages.
2808 	const bool vertexStage   = isVertexStage(m_params.testingStage);
2809 	const bool fragmentStage = (m_params.testingStage == TestingStage::FRAGMENT);
2810 	const bool geometryStage = (m_params.testingStage == TestingStage::GEOMETRY);
2811 	const bool tessellation  = (m_params.testingStage == TestingStage::TESS_CONTROL || m_params.testingStage == TestingStage::TESS_EVAL);
2812 
2813 	const auto& features = context.getDeviceFeatures();
2814 
2815 	if (vertexStage && !features.vertexPipelineStoresAndAtomics)
2816 		TCU_THROW(NotSupportedError, "Vertex pipeline stores and atomics not supported");
2817 
2818 	if (fragmentStage && !features.fragmentStoresAndAtomics)
2819 		TCU_THROW(NotSupportedError, "Fragment shader stores and atomics not supported");
2820 
2821 	if (geometryStage && !features.geometryShader)
2822 		TCU_THROW(NotSupportedError, "Geometry shader not supported");
2823 
2824 	if (tessellation && !features.tessellationShader)
2825 		TCU_THROW(NotSupportedError, "Tessellation shaders not supported");
2826 }
2827 
2828 // What to do at each iteration step. Used to apply UPDATE_AFTER_BIND or not.
2829 enum class Step
2830 {
2831 	UPDATE = 0,
2832 	BIND,
2833 };
2834 
2835 // Create render pass.
buildRenderPass(const DeviceInterface & vkd,VkDevice device,const std::vector<Resource> & resources)2836 Move<VkRenderPass> buildRenderPass (const DeviceInterface& vkd, VkDevice device, const std::vector<Resource>& resources)
2837 {
2838 	const auto imageFormat = getDescriptorImageFormat();
2839 
2840 	std::vector<VkAttachmentDescription>    attachmentDescriptions;
2841 	std::vector<VkAttachmentReference>      attachmentReferences;
2842 	std::vector<deUint32>                   attachmentIndices;
2843 
2844 	for (const auto& resource : resources)
2845 	{
2846 		if (resource.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
2847 		{
2848 			const auto nextIndex = static_cast<deUint32>(attachmentDescriptions.size());
2849 
2850 			const VkAttachmentDescription description = {
2851 				0u,                                 //  VkAttachmentDescriptionFlags	flags;
2852 				imageFormat,                        //  VkFormat						format;
2853 				VK_SAMPLE_COUNT_1_BIT,              //  VkSampleCountFlagBits			samples;
2854 				VK_ATTACHMENT_LOAD_OP_LOAD,         //  VkAttachmentLoadOp				loadOp;
2855 				VK_ATTACHMENT_STORE_OP_DONT_CARE,   //  VkAttachmentStoreOp				storeOp;
2856 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,    //  VkAttachmentLoadOp				stencilLoadOp;
2857 				VK_ATTACHMENT_STORE_OP_DONT_CARE,   //  VkAttachmentStoreOp				stencilStoreOp;
2858 				VK_IMAGE_LAYOUT_GENERAL,            //  VkImageLayout					initialLayout;
2859 				VK_IMAGE_LAYOUT_GENERAL,            //  VkImageLayout					finalLayout;
2860 			};
2861 
2862 			const VkAttachmentReference reference = { nextIndex, VK_IMAGE_LAYOUT_GENERAL };
2863 
2864 			attachmentIndices.push_back(nextIndex);
2865 			attachmentDescriptions.push_back(description);
2866 			attachmentReferences.push_back(reference);
2867 		}
2868 	}
2869 
2870 	const auto attachmentCount = static_cast<deUint32>(attachmentDescriptions.size());
2871 	DE_ASSERT(attachmentCount == static_cast<deUint32>(attachmentIndices.size()));
2872 	DE_ASSERT(attachmentCount == static_cast<deUint32>(attachmentReferences.size()));
2873 
2874 	const VkSubpassDescription subpassDescription =
2875 	{
2876 		0u,                                     //  VkSubpassDescriptionFlags		flags;
2877 		VK_PIPELINE_BIND_POINT_GRAPHICS,        //  VkPipelineBindPoint				pipelineBindPoint;
2878 		attachmentCount,                        //  deUint32						inputAttachmentCount;
2879 		de::dataOrNull(attachmentReferences),   //  const VkAttachmentReference*	pInputAttachments;
2880 		0u,                                     //  deUint32						colorAttachmentCount;
2881 		nullptr,                                //  const VkAttachmentReference*	pColorAttachments;
2882 		0u,                                     //  const VkAttachmentReference*	pResolveAttachments;
2883 		nullptr,                                //  const VkAttachmentReference*	pDepthStencilAttachment;
2884 		0u,                                     //  deUint32						preserveAttachmentCount;
2885 		nullptr,                                //  const deUint32*					pPreserveAttachments;
2886 	};
2887 
2888 	const VkRenderPassCreateInfo renderPassCreateInfo =
2889 	{
2890 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,              //  VkStructureType					sType;
2891 		nullptr,                                                //  const void*						pNext;
2892 		0u,                                                     //  VkRenderPassCreateFlags			flags;
2893 		static_cast<deUint32>(attachmentDescriptions.size()),   //  deUint32						attachmentCount;
2894 		de::dataOrNull(attachmentDescriptions),                 //  const VkAttachmentDescription*	pAttachments;
2895 		1u,                                                     //  deUint32						subpassCount;
2896 		&subpassDescription,                                    //  const VkSubpassDescription*		pSubpasses;
2897 		0u,                                                     //  deUint32						dependencyCount;
2898 		nullptr,                                                //  const VkSubpassDependency*		pDependencies;
2899 	};
2900 
2901 	return createRenderPass(vkd, device, &renderPassCreateInfo);
2902 }
2903 
2904 // Create a graphics pipeline.
buildGraphicsPipeline(const DeviceInterface & vkd,VkDevice device,VkPipelineLayout pipelineLayout,VkShaderModule vertModule,VkShaderModule tescModule,VkShaderModule teseModule,VkShaderModule geomModule,VkShaderModule fragModule,VkRenderPass renderPass)2905 Move<VkPipeline> buildGraphicsPipeline (const DeviceInterface& vkd, VkDevice device, VkPipelineLayout pipelineLayout,
2906 										VkShaderModule vertModule,
2907 										VkShaderModule tescModule,
2908 										VkShaderModule teseModule,
2909 										VkShaderModule geomModule,
2910 										VkShaderModule fragModule,
2911 										VkRenderPass renderPass)
2912 {
2913 	const auto                    extent    = getDefaultExtent();
2914 	const std::vector<VkViewport> viewports (1u, makeViewport(extent));
2915 	const std::vector<VkRect2D>   scissors  (1u, makeRect2D(extent));
2916 	const auto                    hasTess   = (tescModule != DE_NULL || teseModule != DE_NULL);
2917 	const auto                    topology  = (hasTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
2918 
2919 
2920 	const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
2921 
2922 	const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
2923 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    //  VkStructureType							sType;
2924 		nullptr,                                                        //  const void*								pNext;
2925 		0u,                                                             //  VkPipelineInputAssemblyStateCreateFlags	flags;
2926 		topology,                                                       //  VkPrimitiveTopology						topology;
2927 		VK_FALSE,                                                       //  VkBool32								primitiveRestartEnable;
2928 	};
2929 
2930 	const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo = {
2931 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,  //	VkStructureType							sType;
2932 		nullptr,                                                    //	const void*								pNext;
2933 		0u,                                                         //	VkPipelineTessellationStateCreateFlags	flags;
2934 		(hasTess ? 3u : 0u),                                        //	deUint32								patchControlPoints;
2935 	};
2936 
2937 	const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
2938 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,  //  VkStructureType						sType;
2939 		nullptr,                                                //  const void*							pNext;
2940 		0u,                                                     //  VkPipelineViewportStateCreateFlags	flags;
2941 		static_cast<deUint32>(viewports.size()),                //  deUint32							viewportCount;
2942 		de::dataOrNull(viewports),                              //  const VkViewport*					pViewports;
2943 		static_cast<deUint32>(scissors.size()),                 //  deUint32							scissorCount;
2944 		de::dataOrNull(scissors),                               //  const VkRect2D*						pScissors;
2945 	};
2946 
2947 	const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
2948 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //  VkStructureType							sType;
2949 		nullptr,                                                    //  const void*								pNext;
2950 		0u,                                                         //  VkPipelineRasterizationStateCreateFlags	flags;
2951 		VK_FALSE,                                                   //  VkBool32								depthClampEnable;
2952 		(fragModule == DE_NULL ? VK_TRUE : VK_FALSE),               //  VkBool32								rasterizerDiscardEnable;
2953 		VK_POLYGON_MODE_FILL,                                       //  VkPolygonMode							polygonMode;
2954 		VK_CULL_MODE_NONE,                                          //  VkCullModeFlags							cullMode;
2955 		VK_FRONT_FACE_CLOCKWISE,                                    //  VkFrontFace								frontFace;
2956 		VK_FALSE,                                                   //  VkBool32								depthBiasEnable;
2957 		0.0f,                                                       //  float									depthBiasConstantFactor;
2958 		0.0f,                                                       //  float									depthBiasClamp;
2959 		0.0f,                                                       //  float									depthBiasSlopeFactor;
2960 		1.0f,                                                       //  float									lineWidth;
2961 	};
2962 
2963 	const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
2964 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,   //  VkStructureType							sType;
2965 		nullptr,                                                    //  const void*								pNext;
2966 		0u,                                                         //  VkPipelineMultisampleStateCreateFlags	flags;
2967 		VK_SAMPLE_COUNT_1_BIT,                                      //  VkSampleCountFlagBits					rasterizationSamples;
2968 		VK_FALSE,                                                   //  VkBool32								sampleShadingEnable;
2969 		1.0f,                                                       //  float									minSampleShading;
2970 		nullptr,                                                    //  const VkSampleMask*						pSampleMask;
2971 		VK_FALSE,                                                   //  VkBool32								alphaToCoverageEnable;
2972 		VK_FALSE,                                                   //  VkBool32								alphaToOneEnable;
2973 	};
2974 
2975 	const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = initVulkanStructure();
2976 
2977 	const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = initVulkanStructure();
2978 
2979 	return makeGraphicsPipeline(vkd, device, pipelineLayout,
2980 	                            vertModule, tescModule, teseModule, geomModule, fragModule,
2981 	                            renderPass, 0u, &vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo,
2982 	                            (hasTess ? &tessellationStateCreateInfo : nullptr), &viewportStateCreateInfo,
2983 								&rasterizationStateCreateInfo, &multisampleStateCreateInfo,
2984 	                            &depthStencilStateCreateInfo, &colorBlendStateCreateInfo, nullptr);
2985 }
2986 
buildFramebuffer(const DeviceInterface & vkd,VkDevice device,VkRenderPass renderPass,const std::vector<Resource> & resources)2987 Move<VkFramebuffer> buildFramebuffer (const DeviceInterface& vkd, VkDevice device, VkRenderPass renderPass, const std::vector<Resource>& resources)
2988 {
2989 	const auto extent = getDefaultExtent();
2990 
2991 	std::vector<VkImageView> inputAttachments;
2992 	for (const auto& resource : resources)
2993 	{
2994 		if (resource.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
2995 			inputAttachments.push_back(resource.imageView.get());
2996 	}
2997 
2998 	const VkFramebufferCreateInfo framebufferCreateInfo =
2999 	{
3000 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		//	VkStructureType				sType;
3001 		nullptr,										//	const void*					pNext;
3002 		0u,												//	VkFramebufferCreateFlags	flags;
3003 		renderPass,										//	VkRenderPass				renderPass;
3004 		static_cast<deUint32>(inputAttachments.size()),	//	deUint32					attachmentCount;
3005 		de:: dataOrNull(inputAttachments),				//	const VkImageView*			pAttachments;
3006 		extent.width,									//	deUint32					width;
3007 		extent.height,									//	deUint32					height;
3008 		extent.depth,									//	deUint32					layers;
3009 	};
3010 
3011 	return createFramebuffer(vkd, device, &framebufferCreateInfo);
3012 }
3013 
iterate()3014 tcu::TestStatus MutableTypesInstance::iterate ()
3015 {
3016 	const auto device  = m_context.getDevice();
3017 	const auto physDev = m_context.getPhysicalDevice();
3018 	const auto qIndex  = m_context.getUniversalQueueFamilyIndex();
3019 	const auto queue   = m_context.getUniversalQueue();
3020 
3021 	const auto& vki      = m_context.getInstanceInterface();
3022 	const auto& vkd      = m_context.getDeviceInterface();
3023 	auto      & alloc    = m_context.getDefaultAllocator();
3024 	const auto& paramSet = m_params.descriptorSet;
3025 
3026 	const auto numIterations      = paramSet->maxTypes();
3027 	const bool useExternalImage   = needsExternalImage(*m_params.descriptorSet);
3028 	const bool useExternalSampler = needsExternalSampler(*m_params.descriptorSet);
3029 	const auto stageFlags         = m_params.getStageFlags();
3030 	const bool srcSetNeeded       = (m_params.updateType == UpdateType::COPY);
3031 	const bool updateAfterBind    = (m_params.updateMoment == UpdateMoment::UPDATE_AFTER_BIND);
3032 	const auto bindPoint          = m_params.getBindPoint();
3033 	const bool rayTracing         = isRayTracingStage(m_params.testingStage);
3034 	const bool useAABBs           = (m_params.testingStage == TestingStage::INTERSECTION);
3035 
3036 	// Resources for each iteration.
3037 	std::vector<std::vector<Resource>> allResources;
3038 	allResources.reserve(numIterations);
3039 
3040 	// Command pool.
3041 	const auto cmdPool = makeCommandPool(vkd, device, qIndex);
3042 
3043 	// Descriptor pool and set for the active (dst) descriptor set.
3044 	const auto dstPoolFlags   = m_params.getDstPoolCreateFlags();
3045 	const auto dstLayoutFlags = m_params.getDstLayoutCreateFlags();
3046 
3047 	const auto dstPool   = paramSet->makeDescriptorPool(vkd, device, m_params.poolMutableStrategy, dstPoolFlags);
3048 	const auto dstLayout = paramSet->makeDescriptorSetLayout(vkd, device, stageFlags, dstLayoutFlags);
3049 	const auto varCount  = paramSet->getVariableDescriptorCount();
3050 
3051 	using VariableCountInfoPtr = de::MovePtr<VkDescriptorSetVariableDescriptorCountAllocateInfo>;
3052 
3053 	VariableCountInfoPtr dstVariableCountInfo;
3054 	if (varCount)
3055 	{
3056 		dstVariableCountInfo = VariableCountInfoPtr(new VkDescriptorSetVariableDescriptorCountAllocateInfo);
3057 		*dstVariableCountInfo = initVulkanStructure();
3058 
3059 		dstVariableCountInfo->descriptorSetCount = 1u;
3060 		dstVariableCountInfo->pDescriptorCounts  = &(varCount.get());
3061 	}
3062 	const auto dstSet = makeDescriptorSet(vkd, device, dstPool.get(), dstLayout.get(), dstVariableCountInfo.get());
3063 
3064 	// Source pool and set (optional).
3065 	const auto                  srcPoolFlags   = m_params.getSrcPoolCreateFlags();
3066 	const auto                  srcLayoutFlags = m_params.getSrcLayoutCreateFlags();
3067 	DescriptorSetPtr            iterationSrcSet;
3068 	Move<VkDescriptorPool>      srcPool;
3069 	Move<VkDescriptorSetLayout> srcLayout;
3070 	Move<VkDescriptorSet>       srcSet;
3071 
3072 	// Extra set for external resources and output buffer.
3073 	std::vector<Resource> extraResources;
3074 	extraResources.emplace_back(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vkd, device, alloc, qIndex, queue, useAABBs, 0u, numIterations);
3075 	if (useExternalImage)
3076 		extraResources.emplace_back(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vkd, device, alloc, qIndex, queue, useAABBs, getExternalSampledImageValue());
3077 	if (useExternalSampler)
3078 		extraResources.emplace_back(VK_DESCRIPTOR_TYPE_SAMPLER, vkd, device, alloc, qIndex, queue, useAABBs, 0u);
3079 	if (rayTracing)
3080 		extraResources.emplace_back(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, vkd, device, alloc, qIndex, queue, useAABBs, 0u);
3081 
3082 	Move<VkDescriptorPool> extraPool;
3083 	{
3084 		DescriptorPoolBuilder poolBuilder;
3085 		poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
3086 		if (useExternalImage)
3087 			poolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
3088 		if (useExternalSampler)
3089 			poolBuilder.addType(VK_DESCRIPTOR_TYPE_SAMPLER);
3090 		if (rayTracing)
3091 			poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
3092 		extraPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
3093 	}
3094 
3095 	Move<VkDescriptorSetLayout> extraLayout;
3096 	{
3097 		DescriptorSetLayoutBuilder layoutBuilder;
3098 		layoutBuilder.addBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, stageFlags, nullptr);
3099 		if (useExternalImage)
3100 			layoutBuilder.addBinding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1u, stageFlags, nullptr);
3101 		if (useExternalSampler)
3102 			layoutBuilder.addBinding(VK_DESCRIPTOR_TYPE_SAMPLER, 1u, stageFlags, nullptr);
3103 		if (rayTracing)
3104 		{
3105 			// The extra acceleration structure is used from the ray generation shader only.
3106 			layoutBuilder.addBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, VK_SHADER_STAGE_RAYGEN_BIT_KHR, nullptr);
3107 		}
3108 		extraLayout = layoutBuilder.build(vkd, device);
3109 	}
3110 
3111 	const auto extraSet = makeDescriptorSet(vkd, device, extraPool.get(), extraLayout.get());
3112 
3113 	// Update extra set.
3114 	using DescriptorBufferInfoPtr = de::MovePtr<VkDescriptorBufferInfo>;
3115 	using DescriptorImageInfoPtr  = de::MovePtr<VkDescriptorImageInfo>;
3116 	using DescriptorASInfoPtr     = de::MovePtr<VkWriteDescriptorSetAccelerationStructureKHR>;
3117 
3118 	deUint32                bindingCount = 0u;
3119 	DescriptorBufferInfoPtr bufferInfoPtr;
3120 	DescriptorImageInfoPtr  imageInfoPtr;
3121 	DescriptorImageInfoPtr  samplerInfoPtr;
3122 	DescriptorASInfoPtr     asWriteInfoPtr;
3123 
3124     const auto outputBufferSize = static_cast<VkDeviceSize>(sizeof(deUint32) * static_cast<size_t>(numIterations));
3125 	bufferInfoPtr = DescriptorBufferInfoPtr(new VkDescriptorBufferInfo(makeDescriptorBufferInfo(extraResources[bindingCount++].bufferWithMemory->get(), 0ull, outputBufferSize)));
3126 	if (useExternalImage)
3127 		imageInfoPtr = DescriptorImageInfoPtr(new VkDescriptorImageInfo(makeDescriptorImageInfo(DE_NULL, extraResources[bindingCount++].imageView.get(), VK_IMAGE_LAYOUT_GENERAL)));
3128 	if (useExternalSampler)
3129 		samplerInfoPtr = DescriptorImageInfoPtr(new VkDescriptorImageInfo(makeDescriptorImageInfo(extraResources[bindingCount++].sampler.get(), DE_NULL, VK_IMAGE_LAYOUT_GENERAL)));
3130 	if (rayTracing)
3131 	{
3132 		asWriteInfoPtr = DescriptorASInfoPtr(new VkWriteDescriptorSetAccelerationStructureKHR);
3133 		*asWriteInfoPtr = initVulkanStructure();
3134 		asWriteInfoPtr->accelerationStructureCount  = 1u;
3135 		asWriteInfoPtr->pAccelerationStructures     = extraResources[bindingCount++].asData.tlas.get()->getPtr();
3136 	}
3137 
3138 	{
3139 		bindingCount = 0u;
3140 		DescriptorSetUpdateBuilder updateBuilder;
3141 		updateBuilder.writeSingle(extraSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingCount++), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, bufferInfoPtr.get());
3142 		if (useExternalImage)
3143 			updateBuilder.writeSingle(extraSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingCount++), VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, imageInfoPtr.get());
3144 		if (useExternalSampler)
3145 			updateBuilder.writeSingle(extraSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingCount++), VK_DESCRIPTOR_TYPE_SAMPLER, samplerInfoPtr.get());
3146 		if (rayTracing)
3147 			updateBuilder.writeSingle(extraSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingCount++), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, asWriteInfoPtr.get());
3148 		updateBuilder.update(vkd, device);
3149 	}
3150 
3151 	// Push constants.
3152 	const deUint32            zero    = 0u;
3153 	const VkPushConstantRange pcRange = {stageFlags, 0u /*offset*/, static_cast<deUint32>(sizeof(zero)) /*size*/ };
3154 
3155 	// Needed for some test variants.
3156 	Move<VkShaderModule> vertPassthrough;
3157 	Move<VkShaderModule> tesePassthrough;
3158 	Move<VkShaderModule> tescPassthrough;
3159 	Move<VkShaderModule> rgenPassthrough;
3160 	Move<VkShaderModule> missPassthrough;
3161 
3162 	if (m_params.testingStage == TestingStage::FRAGMENT
3163 		|| m_params.testingStage == TestingStage::GEOMETRY
3164 		|| m_params.testingStage == TestingStage::TESS_CONTROL
3165 		|| m_params.testingStage == TestingStage::TESS_EVAL)
3166 	{
3167 		vertPassthrough = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
3168 	}
3169 
3170 	if (m_params.testingStage == TestingStage::TESS_CONTROL)
3171 	{
3172 		tesePassthrough = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
3173 	}
3174 
3175 	if (m_params.testingStage == TestingStage::TESS_EVAL)
3176 	{
3177 		tescPassthrough = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
3178 	}
3179 
3180 	if (m_params.testingStage == TestingStage::CLOSEST_HIT
3181 		|| m_params.testingStage == TestingStage::ANY_HIT
3182 		|| m_params.testingStage == TestingStage::INTERSECTION
3183 		|| m_params.testingStage == TestingStage::MISS
3184 		|| m_params.testingStage == TestingStage::CALLABLE)
3185 	{
3186 		rgenPassthrough = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0u);
3187 	}
3188 
3189 	if (m_params.testingStage == TestingStage::INTERSECTION)
3190 	{
3191 		missPassthrough = createShaderModule(vkd, device, m_context.getBinaryCollection().get("miss"), 0u);
3192 	}
3193 
3194 	for (deUint32 iteration = 0u; iteration < numIterations; ++iteration)
3195 	{
3196 		// Generate source set for the current iteration.
3197 		if (srcSetNeeded)
3198 		{
3199 			// Free previous descriptor set before rebuilding the pool.
3200 			srcSet          = Move<VkDescriptorSet>();
3201 			iterationSrcSet = paramSet->genSourceSet(m_params.sourceSetStrategy, iteration);
3202 			srcPool         = iterationSrcSet->makeDescriptorPool(vkd, device, m_params.poolMutableStrategy, srcPoolFlags);
3203 			srcLayout       = iterationSrcSet->makeDescriptorSetLayout(vkd, device, stageFlags, srcLayoutFlags);
3204 
3205 			const auto srcVarCount = iterationSrcSet->getVariableDescriptorCount();
3206 			VariableCountInfoPtr srcVariableCountInfo;
3207 
3208 			if (srcVarCount)
3209 			{
3210 				srcVariableCountInfo = VariableCountInfoPtr(new VkDescriptorSetVariableDescriptorCountAllocateInfo);
3211 				*srcVariableCountInfo = initVulkanStructure();
3212 
3213 				srcVariableCountInfo->descriptorSetCount = 1u;
3214 				srcVariableCountInfo->pDescriptorCounts = &(srcVarCount.get());
3215 			}
3216 
3217 			srcSet = makeDescriptorSet(vkd, device, srcPool.get(), srcLayout.get(), srcVariableCountInfo.get());
3218 		}
3219 
3220 		// Set layouts and sets used in the pipeline.
3221 		const std::vector<VkDescriptorSetLayout> setLayouts = {dstLayout.get(), extraLayout.get()};
3222 		const std::vector<VkDescriptorSet>       usedSets   = {dstSet.get(), extraSet.get()};
3223 
3224 		// Create resources.
3225 		allResources.emplace_back(paramSet->createResources(vkd, device, alloc, qIndex, queue, iteration, useAABBs));
3226 		const auto& resources = allResources.back();
3227 
3228 		// Make pipeline for the current iteration.
3229 		const auto pipelineLayout = makePipelineLayout(vkd, device, static_cast<deUint32>(setLayouts.size()), de::dataOrNull(setLayouts), 1u, &pcRange);
3230 		const auto moduleName     = shaderName(iteration);
3231 		const auto shaderModule   = createShaderModule(vkd, device, m_context.getBinaryCollection().get(moduleName), 0u);
3232 
3233 		Move<VkPipeline>     pipeline;
3234 		Move<VkRenderPass>   renderPass;
3235 		Move<VkFramebuffer>  framebuffer;
3236 
3237 		deUint32 shaderGroupHandleSize		= 0u;
3238 		deUint32 shaderGroupBaseAlignment	= 1u;
3239 
3240 		de::MovePtr<BufferWithMemory>	raygenSBT;
3241 		de::MovePtr<BufferWithMemory>	missSBT;
3242 		de::MovePtr<BufferWithMemory>	hitSBT;
3243 		de::MovePtr<BufferWithMemory>	callableSBT;
3244 
3245 		VkStridedDeviceAddressRegionKHR	raygenSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
3246 		VkStridedDeviceAddressRegionKHR	missSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
3247 		VkStridedDeviceAddressRegionKHR	hitSBTRegion		= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
3248 		VkStridedDeviceAddressRegionKHR	callableSBTRegion	= makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0);
3249 
3250 		if (bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE)
3251 			pipeline = makeComputePipeline(vkd, device, pipelineLayout.get(), 0u, shaderModule.get(), 0u, nullptr);
3252 		else if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS)
3253 		{
3254 			VkShaderModule vertModule = DE_NULL;
3255 			VkShaderModule teseModule = DE_NULL;
3256 			VkShaderModule tescModule = DE_NULL;
3257 			VkShaderModule geomModule = DE_NULL;
3258 			VkShaderModule fragModule = DE_NULL;
3259 
3260 			if (m_params.testingStage == TestingStage::VERTEX)
3261 				vertModule = shaderModule.get();
3262 			else if (m_params.testingStage == TestingStage::FRAGMENT)
3263 			{
3264 				vertModule = vertPassthrough.get();
3265 				fragModule = shaderModule.get();
3266 			}
3267 			else if (m_params.testingStage == TestingStage::GEOMETRY)
3268 			{
3269 				vertModule = vertPassthrough.get();
3270 				geomModule = shaderModule.get();
3271 			}
3272 			else if (m_params.testingStage == TestingStage::TESS_CONTROL)
3273 			{
3274 				vertModule = vertPassthrough.get();
3275 				teseModule = tesePassthrough.get();
3276 				tescModule = shaderModule.get();
3277 			}
3278 			else if (m_params.testingStage == TestingStage::TESS_EVAL)
3279 			{
3280 				vertModule = vertPassthrough.get();
3281 				tescModule = tescPassthrough.get();
3282 				teseModule = shaderModule.get();
3283 			}
3284 			else
3285 				DE_ASSERT(false);
3286 
3287 			renderPass  = buildRenderPass(vkd, device, resources);
3288 			pipeline    = buildGraphicsPipeline(vkd, device, pipelineLayout.get(), vertModule, tescModule, teseModule, geomModule, fragModule, renderPass.get());
3289 			framebuffer = buildFramebuffer(vkd, device, renderPass.get(), resources);
3290 		}
3291 		else if (bindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
3292 		{
3293 			const auto rayTracingPipeline       = de::newMovePtr<RayTracingPipeline>();
3294 			const auto rayTracingPropertiesKHR	= makeRayTracingProperties(vki, physDev);
3295 			shaderGroupHandleSize				= rayTracingPropertiesKHR->getShaderGroupHandleSize();
3296 			shaderGroupBaseAlignment			= rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
3297 
3298 			VkShaderModule rgenModule = DE_NULL;
3299 			VkShaderModule isecModule = DE_NULL;
3300 			VkShaderModule ahitModule = DE_NULL;
3301 			VkShaderModule chitModule = DE_NULL;
3302 			VkShaderModule missModule = DE_NULL;
3303 			VkShaderModule callModule = DE_NULL;
3304 
3305 			const deUint32  rgenGroup   = 0u;
3306 			deUint32        hitGroup    = 0u;
3307 			deUint32        missGroup   = 0u;
3308 			deUint32        callGroup   = 0u;
3309 
3310 			if (m_params.testingStage == TestingStage::RAY_GEN)
3311 			{
3312 				rgenModule = shaderModule.get();
3313 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3314 			}
3315 			else if (m_params.testingStage == TestingStage::INTERSECTION)
3316 			{
3317 				hitGroup   = 1u;
3318 				missGroup  = 2u;
3319 				rgenModule = rgenPassthrough.get();
3320 				missModule = missPassthrough.get();
3321 				isecModule = shaderModule.get();
3322 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3323 				rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, isecModule, hitGroup);
3324 				rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule, missGroup);
3325 			}
3326 			else if (m_params.testingStage == TestingStage::ANY_HIT)
3327 			{
3328 				hitGroup   = 1u;
3329 				rgenModule = rgenPassthrough.get();
3330 				ahitModule = shaderModule.get();
3331 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3332 				rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, ahitModule, hitGroup);
3333 			}
3334 			else if (m_params.testingStage == TestingStage::CLOSEST_HIT)
3335 			{
3336 				hitGroup   = 1u;
3337 				rgenModule = rgenPassthrough.get();
3338 				chitModule = shaderModule.get();
3339 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3340 				rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, chitModule, hitGroup);
3341 			}
3342 			else if (m_params.testingStage == TestingStage::MISS)
3343 			{
3344 				missGroup  = 1u;
3345 				rgenModule = rgenPassthrough.get();
3346 				missModule = shaderModule.get();
3347 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3348 				rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, missModule, missGroup);
3349 			}
3350 			else if (m_params.testingStage == TestingStage::CALLABLE)
3351 			{
3352 				callGroup  = 1u;
3353 				rgenModule = rgenPassthrough.get();
3354 				callModule = shaderModule.get();
3355 				rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenModule, rgenGroup);
3356 				rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, callModule, callGroup);
3357 			}
3358 			else
3359 				DE_ASSERT(false);
3360 
3361 			pipeline = rayTracingPipeline->createPipeline(vkd, device, pipelineLayout.get());
3362 
3363 			raygenSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, rgenGroup, 1u);
3364 			raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
3365 
3366 			if (missGroup > 0u)
3367 			{
3368 				missSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, missGroup, 1u);
3369 				missSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, missSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
3370 			}
3371 
3372 			if (hitGroup > 0u)
3373 			{
3374 				hitSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, hitGroup, 1u);
3375 				hitSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, hitSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
3376 			}
3377 
3378 			if (callGroup > 0u)
3379 			{
3380 				callableSBT = rayTracingPipeline->createShaderBindingTable(vkd, device, pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, callGroup, 1u);
3381 				callableSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, callableSBT->get(), 0ull), shaderGroupHandleSize, shaderGroupHandleSize);
3382 			}
3383 		}
3384 		else
3385 			DE_ASSERT(false);
3386 
3387 		// Command buffer for the current iteration.
3388 		const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
3389 		const auto cmdBuffer    = cmdBufferPtr.get();
3390 
3391 		beginCommandBuffer(vkd, cmdBuffer);
3392 
3393 		const Step steps[] = {
3394 			(updateAfterBind ? Step::BIND : Step::UPDATE),
3395 			(updateAfterBind ? Step::UPDATE : Step::BIND)
3396 		};
3397 
3398 		for (const auto& step : steps)
3399 		{
3400 			if (step == Step::BIND)
3401 			{
3402 				vkd.cmdBindPipeline(cmdBuffer, bindPoint, pipeline.get());
3403 				vkd.cmdBindDescriptorSets(cmdBuffer, bindPoint, pipelineLayout.get(), 0u, static_cast<deUint32>(usedSets.size()), de::dataOrNull(usedSets), 0u, nullptr);
3404 			}
3405 			else // Step::UPDATE
3406 			{
3407 				if (srcSetNeeded)
3408 				{
3409 					// Note: these operations need to be called on paramSet and not iterationSrcSet. The latter is a compatible set
3410 					// that's correct and contains compatible bindings but, when a binding has been changed from non-mutable to
3411 					// mutable or to an extended mutable type, the list of descriptor types for the mutable bindings in
3412 					// iterationSrcSet are not in iteration order like they are in the original set and must not be taken into
3413 					// account to update or copy sets.
3414 					paramSet->updateDescriptorSet(vkd, device, srcSet.get(), iteration, resources);
3415 					paramSet->copyDescriptorSet(vkd, device, srcSet.get(), dstSet.get());
3416 				}
3417 				else
3418 				{
3419 					paramSet->updateDescriptorSet(vkd, device, dstSet.get(), iteration, resources);
3420 				}
3421 			}
3422 		}
3423 
3424 		// Run shader.
3425 		vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), stageFlags, 0u, static_cast<deUint32>(sizeof(zero)), &zero);
3426 
3427 		if (bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE)
3428 			vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u);
3429 		else if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS)
3430 		{
3431 			const auto extent     = getDefaultExtent();
3432 			const auto renderArea = makeRect2D(extent);
3433 
3434 			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea);
3435 			vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
3436 			endRenderPass(vkd, cmdBuffer);
3437 		}
3438 		else if (bindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR)
3439 		{
3440 			vkd.cmdTraceRaysKHR(cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u);
3441 		}
3442 		else
3443 			DE_ASSERT(false);
3444 
3445 		endCommandBuffer(vkd, cmdBuffer);
3446 		submitCommandsAndWait(vkd, device, queue, cmdBuffer);
3447 
3448 		// Verify output buffer.
3449 		{
3450 			const auto outputBufferVal = extraResources[0].getStoredValue(vkd, device, alloc, qIndex, queue, iteration);
3451 			DE_ASSERT(static_cast<bool>(outputBufferVal));
3452 
3453 			const auto expectedValue = getExpectedOutputBufferValue();
3454 			if (outputBufferVal.get() != expectedValue)
3455 			{
3456 				std::ostringstream msg;
3457 				msg << "Iteration " << iteration << ": unexpected value found in output buffer (expected " << expectedValue << " and found " << outputBufferVal.get() << ")";
3458 				TCU_FAIL(msg.str());
3459 			}
3460 		}
3461 
3462 		// Verify descriptor writes.
3463 		{
3464 			size_t     resourcesOffset = 0;
3465 			const auto writeMask       = getStoredValueMask();
3466 			const auto numBindings     = paramSet->numBindings();
3467 
3468 			for (deUint32 bindingIdx = 0u; bindingIdx < numBindings; ++bindingIdx)
3469 			{
3470 				const auto binding = paramSet->getBinding(bindingIdx);
3471 				const auto bindingTypes = binding->typesAtIteration(iteration);
3472 
3473 				for (size_t descriptorIdx = 0; descriptorIdx < bindingTypes.size(); ++descriptorIdx)
3474 				{
3475 					const auto& descriptorType = bindingTypes[descriptorIdx];
3476 					if (!isShaderWritable(descriptorType))
3477 						continue;
3478 
3479 					const auto& resource        = resources[resourcesOffset + descriptorIdx];
3480 					const auto  initialValue    = resource.initialValue;
3481 					const auto  storedValuePtr  = resource.getStoredValue(vkd, device, alloc, qIndex, queue);
3482 
3483 					DE_ASSERT(static_cast<bool>(storedValuePtr));
3484 					const auto storedValue   = storedValuePtr.get();
3485 					const auto expectedValue = (initialValue | writeMask);
3486 					if (expectedValue != storedValue)
3487 					{
3488 						std::ostringstream msg;
3489 						msg << "Iteration " << iteration << ": descriptor at binding " << bindingIdx << " index " << descriptorIdx
3490 						    << " with type " << de::toString(descriptorType) << " contains unexpected value " << std::hex
3491 							<< storedValue << " (expected " << expectedValue << ")";
3492 						TCU_FAIL(msg.str());
3493 					}
3494 				}
3495 
3496 				resourcesOffset += bindingTypes.size();
3497 			}
3498 		}
3499 	}
3500 
3501 	return tcu::TestStatus::pass("Pass");
3502 }
3503 
3504 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
3505 
createMutableTestVariants(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup,const DescriptorSetPtr & descriptorSet,const std::vector<TestingStage> & stagesToTest)3506 void createMutableTestVariants (tcu::TestContext& testCtx, tcu::TestCaseGroup* parentGroup, const DescriptorSetPtr& descriptorSet, const std::vector<TestingStage>& stagesToTest)
3507 {
3508 	const struct
3509 	{
3510 		UpdateType  updateType;
3511 		const char* name;
3512 	} updateTypes[] = {
3513 		{UpdateType::WRITE, "update_write"},
3514 		{UpdateType::COPY,  "update_copy"},
3515 	};
3516 
3517 	const struct
3518 	{
3519 		SourceSetStrategy   sourceSetStrategy;
3520 		const char*         name;
3521 	} sourceStrategies[] = {
3522 		{SourceSetStrategy::MUTABLE,    "mutable_source"},
3523 		{SourceSetStrategy::NONMUTABLE, "nonmutable_source"},
3524 		{SourceSetStrategy::NO_SOURCE,  "no_source"},
3525 	};
3526 
3527 	const struct
3528 	{
3529 		SourceSetType   sourceSetType;
3530 		const char*     name;
3531 	} sourceTypes[] = {
3532 		{SourceSetType::NORMAL,    "normal_source"},
3533 		{SourceSetType::HOST_ONLY, "host_only_source"},
3534 		{SourceSetType::NO_SOURCE, "no_source"},
3535 	};
3536 
3537 	const struct
3538 	{
3539 		PoolMutableStrategy poolMutableStrategy;
3540 		const char*         name;
3541 	} poolStrategies[] = {
3542 		{PoolMutableStrategy::KEEP_TYPES,   "pool_same_types"},
3543 		{PoolMutableStrategy::NO_TYPES,     "pool_no_types"},
3544 		{PoolMutableStrategy::EXPAND_TYPES, "pool_expand_types"},
3545 	};
3546 
3547 	const struct
3548 	{
3549 		UpdateMoment    updateMoment;
3550 		const char*     name;
3551 	} updateMoments[] = {
3552 		{UpdateMoment::NORMAL,            "pre_update"},
3553 		{UpdateMoment::UPDATE_AFTER_BIND, "update_after_bind"},
3554 	};
3555 
3556 	const struct
3557 	{
3558 		ArrayAccessType arrayAccessType;
3559 		const char*     name;
3560 	} arrayAccessTypes[] = {
3561 		{ArrayAccessType::CONSTANT,      "index_constant"},
3562 		{ArrayAccessType::PUSH_CONSTANT, "index_push_constant"},
3563 		{ArrayAccessType::NO_ARRAY,      "no_array"},
3564 	};
3565 
3566 	const struct StageAndName
3567 	{
3568 		TestingStage    testingStage;
3569 		const char*     name;
3570 	} testStageList[] = {
3571 		{TestingStage::COMPUTE,      "comp"},
3572 		{TestingStage::VERTEX,       "vert"},
3573 		{TestingStage::TESS_CONTROL, "tesc"},
3574 		{TestingStage::TESS_EVAL,    "tese"},
3575 		{TestingStage::GEOMETRY,     "geom"},
3576 		{TestingStage::FRAGMENT,     "frag"},
3577 		{TestingStage::RAY_GEN,      "rgen"},
3578 		{TestingStage::INTERSECTION, "isec"},
3579 		{TestingStage::ANY_HIT,      "ahit"},
3580 		{TestingStage::CLOSEST_HIT,  "chit"},
3581 		{TestingStage::MISS,         "miss"},
3582 		{TestingStage::CALLABLE,     "call"},
3583 	};
3584 
3585 	const bool hasArrays           = descriptorSet->hasArrays();
3586 	const bool hasInputAttachments = usesInputAttachments(*descriptorSet);
3587 
3588 	for (const auto& ut : updateTypes)
3589 	{
3590 		GroupPtr updateGroup(new tcu::TestCaseGroup(testCtx, ut.name, ""));
3591 
3592 		for (const auto& srcStrategy : sourceStrategies)
3593 		{
3594 			// Skip combinations that make no sense.
3595 			if (ut.updateType == UpdateType::WRITE && srcStrategy.sourceSetStrategy != SourceSetStrategy::NO_SOURCE)
3596 				continue;
3597 
3598 			if (ut.updateType == UpdateType::COPY && srcStrategy.sourceSetStrategy == SourceSetStrategy::NO_SOURCE)
3599 				continue;
3600 
3601 			if (srcStrategy.sourceSetStrategy == SourceSetStrategy::NONMUTABLE && descriptorSet->needsAnyAliasing())
3602 				continue;
3603 
3604 			GroupPtr srcStrategyGroup(new tcu::TestCaseGroup(testCtx, srcStrategy.name, ""));
3605 
3606 			for (const auto& srcType : sourceTypes)
3607 			{
3608 				// Skip combinations that make no sense.
3609 				if (ut.updateType == UpdateType::WRITE && srcType.sourceSetType != SourceSetType::NO_SOURCE)
3610 					continue;
3611 
3612 				if (ut.updateType == UpdateType::COPY && srcType.sourceSetType == SourceSetType::NO_SOURCE)
3613 					continue;
3614 
3615 				GroupPtr srcTypeGroup(new tcu::TestCaseGroup(testCtx, srcType.name, ""));
3616 
3617 				for (const auto& poolStrategy: poolStrategies)
3618 				{
3619 					GroupPtr poolStrategyGroup(new tcu::TestCaseGroup(testCtx, poolStrategy.name, ""));
3620 
3621 					for (const auto& moment : updateMoments)
3622 					{
3623 						//if (moment.updateMoment == UpdateMoment::UPDATE_AFTER_BIND && srcType.sourceSetType == SourceSetType::HOST_ONLY)
3624 						//	continue;
3625 
3626 						if (moment.updateMoment == UpdateMoment::UPDATE_AFTER_BIND && hasInputAttachments)
3627 							continue;
3628 
3629 						GroupPtr momentGroup(new tcu::TestCaseGroup(testCtx, moment.name, ""));
3630 
3631 						for (const auto& accessType : arrayAccessTypes)
3632 						{
3633 							// Skip combinations that make no sense.
3634 							if (hasArrays && accessType.arrayAccessType == ArrayAccessType::NO_ARRAY)
3635 								continue;
3636 
3637 							if (!hasArrays && accessType.arrayAccessType != ArrayAccessType::NO_ARRAY)
3638 								continue;
3639 
3640 							GroupPtr accessTypeGroup(new tcu::TestCaseGroup(testCtx, accessType.name, ""));
3641 
3642 							for (const auto& testStage : stagesToTest)
3643 							{
3644 								const auto beginItr = std::begin(testStageList);
3645 								const auto endItr   = std::end(testStageList);
3646 								const auto iter     = std::find_if(beginItr, endItr, [testStage] (const StageAndName& ts) { return ts.testingStage == testStage; });
3647 
3648 								DE_ASSERT(iter != endItr);
3649 								const auto& stage = *iter;
3650 
3651 								if (hasInputAttachments && stage.testingStage != TestingStage::FRAGMENT)
3652 									continue;
3653 
3654 								TestParams params = {
3655 									descriptorSet,
3656 									ut.updateType,
3657 									srcStrategy.sourceSetStrategy,
3658 									srcType.sourceSetType,
3659 									poolStrategy.poolMutableStrategy,
3660 									moment.updateMoment,
3661 									accessType.arrayAccessType,
3662 									stage.testingStage,
3663 								};
3664 
3665 								accessTypeGroup->addChild(new MutableTypesTest(testCtx, stage.name, "", params));
3666 							}
3667 
3668 							momentGroup->addChild(accessTypeGroup.release());
3669 						}
3670 
3671 						poolStrategyGroup->addChild(momentGroup.release());
3672 					}
3673 
3674 					srcTypeGroup->addChild(poolStrategyGroup.release());
3675 				}
3676 
3677 				srcStrategyGroup->addChild(srcTypeGroup.release());
3678 			}
3679 
3680 			updateGroup->addChild(srcStrategyGroup.release());
3681 		}
3682 
3683 		parentGroup->addChild(updateGroup.release());
3684 	}
3685 }
3686 
3687 }
3688 
descriptorTypeStr(VkDescriptorType descriptorType)3689 std::string descriptorTypeStr (VkDescriptorType descriptorType)
3690 {
3691 	static const auto prefixLen = std::string("VK_DESCRIPTOR_TYPE_").size();
3692 	return de::toLower(de::toString(descriptorType).substr(prefixLen));
3693 }
3694 
createDescriptorValveMutableTests(tcu::TestContext & testCtx)3695 tcu::TestCaseGroup* createDescriptorValveMutableTests (tcu::TestContext& testCtx)
3696 {
3697 	GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "mutable_descriptor", "Tests for VK_VALVE_mutable_descriptor_type"));
3698 
3699 	const VkDescriptorType basicDescriptorTypes[] = {
3700 		VK_DESCRIPTOR_TYPE_SAMPLER,
3701 		VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
3702 		VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
3703 		VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
3704 		VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
3705 		VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
3706 		VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
3707 		VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
3708 		VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
3709 		VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
3710 	};
3711 
3712 	static const auto mandatoryTypes = getMandatoryMutableTypes();
3713 
3714 	using StageVec = std::vector<TestingStage>;
3715 
3716 	const StageVec allStages =
3717 	{
3718 		TestingStage::COMPUTE,
3719 		TestingStage::VERTEX,
3720 		TestingStage::TESS_CONTROL,
3721 		TestingStage::TESS_EVAL,
3722 		TestingStage::GEOMETRY,
3723 		TestingStage::FRAGMENT,
3724 		TestingStage::RAY_GEN,
3725 		TestingStage::INTERSECTION,
3726 		TestingStage::ANY_HIT,
3727 		TestingStage::CLOSEST_HIT,
3728 		TestingStage::MISS,
3729 		TestingStage::CALLABLE,
3730 	};
3731 
3732 	const StageVec reducedStages =
3733 	{
3734 		TestingStage::COMPUTE,
3735 		TestingStage::VERTEX,
3736 		TestingStage::FRAGMENT,
3737 		TestingStage::RAY_GEN,
3738 	};
3739 
3740 	const StageVec computeOnly =
3741 	{
3742 		TestingStage::COMPUTE,
3743 	};
3744 
3745 	// Basic tests with a single mutable descriptor.
3746 	{
3747 		GroupPtr singleCases(new tcu::TestCaseGroup(testCtx, "single", "Basic mutable descriptor tests with a single mutable descriptor"));
3748 
3749 		for (const auto& descriptorType : basicDescriptorTypes)
3750 		{
3751 			const auto                          groupName = descriptorTypeStr(descriptorType);
3752 			const std::vector<VkDescriptorType> actualTypes(1u, descriptorType);
3753 
3754 			DescriptorSetPtr setPtr;
3755 			{
3756 				DescriptorSet::BindingPtrVector setBindings;
3757 				setBindings.emplace_back(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, actualTypes));
3758 				setPtr = DescriptorSetPtr(new DescriptorSet(setBindings));
3759 			}
3760 
3761 			GroupPtr subGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), ""));
3762 			createMutableTestVariants(testCtx, subGroup.get(), setPtr, allStages);
3763 
3764 			singleCases->addChild(subGroup.release());
3765 		}
3766 
3767 		// Case with a single descriptor that iterates several types.
3768 		{
3769 			DescriptorSetPtr setPtr;
3770 			{
3771 				DescriptorSet::BindingPtrVector setBindings;
3772 				setBindings.emplace_back(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, mandatoryTypes));
3773 				setPtr = DescriptorSetPtr(new DescriptorSet(setBindings));
3774 			}
3775 
3776 			GroupPtr subGroup(new tcu::TestCaseGroup(testCtx, "all_mandatory", ""));
3777 			createMutableTestVariants(testCtx, subGroup.get(), setPtr, reducedStages);
3778 
3779 			singleCases->addChild(subGroup.release());
3780 		}
3781 
3782 		// Cases that try to verify switching from any descriptor type to any other is possible.
3783 		{
3784 			GroupPtr subGroup(new tcu::TestCaseGroup(testCtx, "switches", "Test switching from one to another descriptor type works as expected"));
3785 
3786 			for (const auto& initialDescriptorType : basicDescriptorTypes)
3787 			{
3788 				for (const auto& finalDescriptorType : basicDescriptorTypes)
3789 				{
3790 					if (initialDescriptorType == finalDescriptorType)
3791 						continue;
3792 
3793 					const std::vector<VkDescriptorType> mutableTypes { initialDescriptorType, finalDescriptorType };
3794 					DescriptorSet::BindingPtrVector setBindings;
3795 					setBindings.emplace_back(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, mutableTypes));
3796 
3797 					DescriptorSetPtr setPtr = DescriptorSetPtr(new DescriptorSet(setBindings));
3798 
3799 					const auto groupName = descriptorTypeStr(initialDescriptorType) + "_" + descriptorTypeStr(finalDescriptorType);
3800 					GroupPtr combinationGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), ""));
3801 					createMutableTestVariants(testCtx, combinationGroup.get(), setPtr, reducedStages);
3802 					subGroup->addChild(combinationGroup.release());
3803 				}
3804 			}
3805 
3806 			singleCases->addChild(subGroup.release());
3807 		}
3808 
3809 		mainGroup->addChild(singleCases.release());
3810 	}
3811 
3812 	// Cases with a single non-mutable descriptor. This provides some basic checks to verify copying to non-mutable bindings works.
3813 	{
3814 		GroupPtr singleNonMutableGroup (new tcu::TestCaseGroup(testCtx, "single_nonmutable", "Tests using a single non-mutable descriptor"));
3815 
3816 		for (const auto& descriptorType : basicDescriptorTypes)
3817 		{
3818 			DescriptorSet::BindingPtrVector bindings;
3819 			bindings.emplace_back(new SingleBinding(descriptorType, std::vector<VkDescriptorType>()));
3820 			DescriptorSetPtr descriptorSet (new DescriptorSet(bindings));
3821 
3822 			const auto groupName = descriptorTypeStr(descriptorType);
3823 			GroupPtr descGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), ""));
3824 
3825 			createMutableTestVariants(testCtx, descGroup.get(), descriptorSet, reducedStages);
3826 			singleNonMutableGroup->addChild(descGroup.release());
3827 		}
3828 
3829 		mainGroup->addChild(singleNonMutableGroup.release());
3830 	}
3831 
3832 	const struct {
3833 		bool unbounded;
3834 		const char* name;
3835 	} unboundedCases[] = {
3836 		{false, "constant_size"},
3837 		{true,  "unbounded"},
3838 	};
3839 
3840 	const struct {
3841 		bool aliasing;
3842 		const char* name;
3843 	} aliasingCases[] = {
3844 		{false, "noaliasing"},
3845 		{true,  "aliasing"},
3846 	};
3847 
3848 	const struct {
3849 		bool oneArrayOnly;
3850 		bool mixNonMutable;
3851 		const char* groupName;
3852 		const char* groupDesc;
3853 	} arrayCountGroups[] = {
3854 		{true,  false, "one_array",             "Tests using an array of mutable descriptors"},
3855 		{false, false, "multiple_arrays",       "Tests using multiple arrays of mutable descriptors"},
3856 		{false, true,  "multiple_arrays_mixed", "Tests using multiple arrays of mutable descriptors mixed with arrays of nonmutable ones"},
3857 	};
3858 
3859 	for (const auto& variant : arrayCountGroups)
3860 	{
3861 		GroupPtr arrayGroup(new tcu::TestCaseGroup(testCtx, variant.groupName, variant.groupDesc));
3862 
3863 		for (const auto& unboundedCase : unboundedCases)
3864 		{
3865 			GroupPtr unboundedGroup(new tcu::TestCaseGroup(testCtx, unboundedCase.name, ""));
3866 
3867 			for (const auto& aliasingCase : aliasingCases)
3868 			{
3869 				GroupPtr aliasingGroup(new tcu::TestCaseGroup(testCtx, aliasingCase.name, ""));
3870 
3871 				DescriptorSet::BindingPtrVector setBindings;
3872 
3873 				// Prepare descriptors for this test variant.
3874 				for (size_t mandatoryTypesRotation = 0; mandatoryTypesRotation < mandatoryTypes.size(); ++mandatoryTypesRotation)
3875 				{
3876 					const bool isLastBinding = (variant.oneArrayOnly || mandatoryTypesRotation == mandatoryTypes.size() - 1u);
3877 					const bool isUnbounded   = (unboundedCase.unbounded && isLastBinding);
3878 
3879 					// Create a rotation of the mandatory types for each mutable array binding.
3880 					auto mandatoryTypesVector = mandatoryTypes;
3881 					{
3882 						const auto beginPtr = &mandatoryTypesVector[0];
3883 						const auto endPtr   = beginPtr + mandatoryTypesVector.size();
3884 						std::rotate(beginPtr, &mandatoryTypesVector[mandatoryTypesRotation], endPtr);
3885 					}
3886 
3887 					std::vector<SingleBinding> arrayBindings;
3888 
3889 					if (aliasingCase.aliasing)
3890 					{
3891 						// With aliasing, the descriptor types rotate in each descriptor.
3892 						for (size_t typeIdx = 0; typeIdx < mandatoryTypesVector.size(); ++typeIdx)
3893 						{
3894 							auto       rotatedTypes = mandatoryTypesVector;
3895 							const auto beginPtr     = &rotatedTypes[0];
3896 							const auto endPtr       = beginPtr + rotatedTypes.size();
3897 
3898 							std::rotate(beginPtr, &rotatedTypes[typeIdx], endPtr);
3899 
3900 							arrayBindings.emplace_back(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, rotatedTypes);
3901 						}
3902 					}
3903 					else
3904 					{
3905 						// Without aliasing, all descriptors use the same type at the same time.
3906 						const SingleBinding noAliasingBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, mandatoryTypesVector);
3907 						arrayBindings.resize(mandatoryTypesVector.size(), noAliasingBinding);
3908 					}
3909 
3910 					setBindings.emplace_back(new ArrayBinding(isUnbounded, arrayBindings));
3911 
3912 					if (variant.mixNonMutable && !isUnbounded)
3913 					{
3914 						// Create a non-mutable array binding interleaved with the other ones.
3915 						const SingleBinding nonMutableBinding(mandatoryTypes[mandatoryTypesRotation], std::vector<VkDescriptorType>());
3916 						std::vector<SingleBinding> nonMutableBindings(mandatoryTypes.size(), nonMutableBinding);
3917 						setBindings.emplace_back(new ArrayBinding(false, nonMutableBindings));
3918 					}
3919 
3920 					if (variant.oneArrayOnly)
3921 						break;
3922 				}
3923 
3924 				DescriptorSetPtr descriptorSet(new DescriptorSet(setBindings));
3925 				createMutableTestVariants(testCtx, aliasingGroup.get(), descriptorSet, computeOnly);
3926 
3927 				unboundedGroup->addChild(aliasingGroup.release());
3928 			}
3929 
3930 			arrayGroup->addChild(unboundedGroup.release());
3931 		}
3932 
3933 		mainGroup->addChild(arrayGroup.release());
3934 	}
3935 
3936 	// Cases with a single mutable binding followed by an array of mutable bindings.
3937 	// The array will use a single type beyond the mandatory ones.
3938 	{
3939 		GroupPtr singleAndArrayGroup(new tcu::TestCaseGroup(testCtx, "single_and_array", "Tests using a single mutable binding followed by a mutable array binding"));
3940 
3941 		for (const auto& descriptorType : basicDescriptorTypes)
3942 		{
3943 			// Input attachments will not use arrays.
3944 			if (descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
3945 				continue;
3946 
3947 			if (de::contains(begin(mandatoryTypes), end(mandatoryTypes), descriptorType))
3948 				continue;
3949 
3950 			const auto groupName = descriptorTypeStr(descriptorType);
3951 			GroupPtr descTypeGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), ""));
3952 
3953 			for (const auto& aliasingCase : aliasingCases)
3954 			{
3955 				GroupPtr aliasingGroup(new tcu::TestCaseGroup(testCtx, aliasingCase.name, ""));
3956 
3957 				DescriptorSet::BindingPtrVector setBindings;
3958 				std::vector<SingleBinding> arrayBindings;
3959 
3960 				// Single mutable descriptor as the first binding.
3961 				setBindings.emplace_back(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, mandatoryTypes));
3962 
3963 				// Descriptor array as the second binding.
3964 				auto arrayBindingDescTypes = mandatoryTypes;
3965 				arrayBindingDescTypes.push_back(descriptorType);
3966 
3967 				if (aliasingCase.aliasing)
3968 				{
3969 					// With aliasing, the descriptor types rotate in each descriptor.
3970 					for (size_t typeIdx = 0; typeIdx < arrayBindingDescTypes.size(); ++typeIdx)
3971 					{
3972 						auto       rotatedTypes = arrayBindingDescTypes;
3973 						const auto beginPtr     = &rotatedTypes[0];
3974 						const auto endPtr       = beginPtr + rotatedTypes.size();
3975 
3976 						std::rotate(beginPtr, &rotatedTypes[typeIdx], endPtr);
3977 
3978 						arrayBindings.emplace_back(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, rotatedTypes);
3979 					}
3980 				}
3981 				else
3982 				{
3983 					// Without aliasing, all descriptors use the same type at the same time.
3984 					const SingleBinding noAliasingBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, arrayBindingDescTypes);
3985 					arrayBindings.resize(arrayBindingDescTypes.size(), noAliasingBinding);
3986 				}
3987 
3988 				// Second binding: array binding.
3989 				setBindings.emplace_back(new ArrayBinding(false/*unbounded*/, arrayBindings));
3990 
3991 				// Create set and test variants.
3992 				DescriptorSetPtr descriptorSet(new DescriptorSet(setBindings));
3993 				createMutableTestVariants(testCtx, aliasingGroup.get(), descriptorSet, computeOnly);
3994 
3995 				descTypeGroup->addChild(aliasingGroup.release());
3996 			}
3997 
3998 			singleAndArrayGroup->addChild(descTypeGroup.release());
3999 		}
4000 
4001 		mainGroup->addChild(singleAndArrayGroup.release());
4002 	}
4003 
4004 	// Cases with several mutable non-array bindings.
4005 	{
4006 		GroupPtr multipleGroup    (new tcu::TestCaseGroup(testCtx, "multiple", "Tests using multiple mutable bindings"));
4007 		GroupPtr mutableOnlyGroup (new tcu::TestCaseGroup(testCtx, "mutable_only", "Tests using only mutable descriptors"));
4008 		GroupPtr mixedGroup       (new tcu::TestCaseGroup(testCtx, "mixed", "Tests mixing mutable descriptors an non-mutable descriptors"));
4009 
4010 		// Each descriptor will have a different type in every iteration, like in the one_array aliasing case.
4011 		for (int groupIdx = 0; groupIdx < 2; ++groupIdx)
4012 		{
4013 			const bool mixed = (groupIdx == 1);
4014 			DescriptorSet::BindingPtrVector setBindings;
4015 
4016 			for (size_t typeIdx = 0; typeIdx < mandatoryTypes.size(); ++typeIdx)
4017 			{
4018 				auto       rotatedTypes = mandatoryTypes;
4019 				const auto beginPtr     = &rotatedTypes[0];
4020 				const auto endPtr       = beginPtr + rotatedTypes.size();
4021 
4022 				std::rotate(beginPtr, &rotatedTypes[typeIdx], endPtr);
4023 				setBindings.emplace_back(new SingleBinding(VK_DESCRIPTOR_TYPE_MUTABLE_VALVE, rotatedTypes));
4024 
4025 				// Additional non-mutable binding interleaved with the mutable ones.
4026 				if (mixed)
4027 					setBindings.emplace_back(new SingleBinding(rotatedTypes[0], std::vector<VkDescriptorType>()));
4028 			}
4029 			DescriptorSetPtr descriptorSet(new DescriptorSet(setBindings));
4030 
4031 			const auto dstGroup = (mixed ? mixedGroup.get() : mutableOnlyGroup.get());
4032 			createMutableTestVariants(testCtx, dstGroup, descriptorSet, computeOnly);
4033 		}
4034 
4035 		multipleGroup->addChild(mutableOnlyGroup.release());
4036 		multipleGroup->addChild(mixedGroup.release());
4037 		mainGroup->addChild(multipleGroup.release());
4038 	}
4039 
4040 	return mainGroup.release();
4041 }
4042 
4043 } // BindingModel
4044 } // vkt
4045