1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Binding shader access tests
22 *//*--------------------------------------------------------------------*/
23
24#include "vktBindingShaderAccessTests.hpp"
25
26#include "vktTestCase.hpp"
27
28#include "vkDefs.hpp"
29#include "vkRef.hpp"
30#include "vkRefUtil.hpp"
31#include "vkPlatform.hpp"
32#include "vkPrograms.hpp"
33#include "vkMemUtil.hpp"
34#include "vkBuilderUtil.hpp"
35#include "vkQueryUtil.hpp"
36#include "vkImageUtil.hpp"
37#include "vkTypeUtil.hpp"
38
39#include "tcuVector.hpp"
40#include "tcuVectorUtil.hpp"
41#include "tcuTexture.hpp"
42#include "tcuTextureUtil.hpp"
43#include "tcuResultCollector.hpp"
44#include "tcuTestLog.hpp"
45#include "tcuRGBA.hpp"
46#include "tcuSurface.hpp"
47#include "tcuImageCompare.hpp"
48
49#include "deUniquePtr.hpp"
50#include "deSharedPtr.hpp"
51#include "deStringUtil.hpp"
52#include "deArrayUtil.hpp"
53
54#include "qpInfo.h"
55#include <iostream>
56
57namespace vkt
58{
59namespace BindingModel
60{
61namespace
62{
63
64enum ResourceFlag
65{
66	RESOURCE_FLAG_IMMUTABLE_SAMPLER = (1u << 0u),
67
68	RESOURCE_FLAG_LAST				= (1u << 1u)
69};
70
71enum DescriptorUpdateMethod
72{
73	DESCRIPTOR_UPDATE_METHOD_NORMAL = 0,			//!< use vkUpdateDescriptorSets
74	DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE,			//!< use descriptor update templates
75	DESCRIPTOR_UPDATE_METHOD_WITH_PUSH,				//!< use push descriptor updates
76	DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE,	//!< use push descriptor update templates
77
78	DESCRIPTOR_UPDATE_METHOD_LAST
79};
80
81std::string stringifyDescriptorUpdateMethod(DescriptorUpdateMethod method)
82{
83	switch (method)
84	{
85		case DESCRIPTOR_UPDATE_METHOD_NORMAL:
86			return "";
87			break;
88
89		case DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE:
90			return "with_template";
91			break;
92
93		case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH:
94			return "with_push";
95			break;
96
97		case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE:
98			return "with_push_template";
99			break;
100
101		default:
102			return "N/A";
103			break;
104	}
105}
106
107static const char* const s_quadrantGenVertexPosSource =	"	highp int quadPhase = gl_VertexIndex % 6;\n"
108														"	highp int quadXcoord = int(quadPhase == 1 || quadPhase == 4 || quadPhase == 5);\n"
109														"	highp int quadYcoord = int(quadPhase == 2 || quadPhase == 3 || quadPhase == 5);\n"
110														"	highp int quadOriginX = (gl_VertexIndex / 6) % 2;\n"
111														"	highp int quadOriginY = (gl_VertexIndex / 6) / 2;\n"
112														"	quadrant_id = gl_VertexIndex / 6;\n"
113														"	result_position = vec4(float(quadOriginX + quadXcoord - 1), float(quadOriginY + quadYcoord - 1), 0.0, 1.0);\n";
114
115std::string genPerVertexBlock (const vk::VkShaderStageFlagBits stage, const glu::GLSLVersion version)
116{
117	static const char* const block = "gl_PerVertex {\n"
118									 "    vec4  gl_Position;\n"
119									 "    float gl_PointSize;\n"	// not used, but for compatibility with how implicit block is declared in ES
120									 "}";
121	std::ostringstream str;
122
123	if (!glu::glslVersionIsES(version))
124		switch (stage)
125		{
126			case vk::VK_SHADER_STAGE_VERTEX_BIT:
127				str << "out " << block << ";\n";
128				break;
129
130			case vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
131				str << "in " << block << " gl_in[gl_MaxPatchVertices];\n"
132					<< "out " << block << " gl_out[];\n";
133				break;
134
135			case vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
136				str << "in " << block << " gl_in[gl_MaxPatchVertices];\n"
137					<< "out " << block << ";\n";
138				break;
139
140			case vk::VK_SHADER_STAGE_GEOMETRY_BIT:
141				str << "in " << block << " gl_in[];\n"
142					<< "out " << block << ";\n";
143				break;
144
145			default:
146				break;
147		}
148
149	return str.str();
150}
151
152bool isUniformDescriptorType (vk::VkDescriptorType type)
153{
154	return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
155		   type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
156		   type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
157}
158
159bool isDynamicDescriptorType (vk::VkDescriptorType type)
160{
161	return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || type == vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
162}
163
164void verifyDriverSupport(const deUint32							apiVersion,
165						 const vk::VkPhysicalDeviceFeatures&	deviceFeatures,
166						 const std::vector<std::string>&		deviceExtensions,
167						 DescriptorUpdateMethod					updateMethod,
168						 vk::VkDescriptorType					descType,
169						 vk::VkShaderStageFlags					activeStages)
170{
171	std::vector<std::string>	extensionNames;
172	size_t						numExtensionsNeeded = 0;
173
174	switch (updateMethod)
175	{
176		case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH:
177			extensionNames.push_back("VK_KHR_push_descriptor");
178			break;
179
180		// fall through
181		case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE:
182			extensionNames.push_back("VK_KHR_push_descriptor");
183		case DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE:
184			if (!vk::isCoreDeviceExtension(apiVersion, "VK_KHR_descriptor_update_template"))
185				extensionNames.push_back("VK_KHR_descriptor_update_template");
186			break;
187
188		case DESCRIPTOR_UPDATE_METHOD_NORMAL:
189			// no extensions needed
190			break;
191
192		default:
193			DE_FATAL("Impossible");
194	}
195
196	numExtensionsNeeded = extensionNames.size();
197
198	if (numExtensionsNeeded > 0)
199	{
200		for (size_t deviceExtNdx = 0; deviceExtNdx < deviceExtensions.size(); deviceExtNdx++)
201		{
202			for (size_t requiredExtNdx = 0; requiredExtNdx < extensionNames.size(); requiredExtNdx++)
203			{
204				if (deStringEqual(deviceExtensions[deviceExtNdx].c_str(), extensionNames[requiredExtNdx].c_str()))
205				{
206					--numExtensionsNeeded;
207					break;
208				}
209			}
210
211			if (numExtensionsNeeded == 0)
212				break;
213		}
214
215		if (numExtensionsNeeded > 0)
216		{
217			TCU_THROW(NotSupportedError, (stringifyDescriptorUpdateMethod(updateMethod) + " tests are not supported").c_str());
218		}
219	}
220
221	switch (descType)
222	{
223		case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
224		case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
225		case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
226		case vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
227		case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
228		case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
229			// These are supported in all stages
230			return;
231
232		case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
233		case vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
234		case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
235		case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
236			if (activeStages & (vk::VK_SHADER_STAGE_VERTEX_BIT |
237								vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT |
238								vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
239								vk::VK_SHADER_STAGE_GEOMETRY_BIT))
240			{
241				if (!deviceFeatures.vertexPipelineStoresAndAtomics)
242					TCU_THROW(NotSupportedError, (de::toString(descType) + " is not supported in the vertex pipeline").c_str());
243			}
244
245			if (activeStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT)
246			{
247				if (!deviceFeatures.fragmentStoresAndAtomics)
248					TCU_THROW(NotSupportedError, (de::toString(descType) + " is not supported in fragment shaders").c_str());
249			}
250			return;
251
252		default:
253			DE_FATAL("Impossible");
254	}
255}
256
257vk::VkImageType viewTypeToImageType (vk::VkImageViewType type)
258{
259	switch (type)
260	{
261		case vk::VK_IMAGE_VIEW_TYPE_1D:
262		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return vk::VK_IMAGE_TYPE_1D;
263		case vk::VK_IMAGE_VIEW_TYPE_2D:
264		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return vk::VK_IMAGE_TYPE_2D;
265		case vk::VK_IMAGE_VIEW_TYPE_3D:			return vk::VK_IMAGE_TYPE_3D;
266		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
267		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return vk::VK_IMAGE_TYPE_2D;
268
269		default:
270			DE_FATAL("Impossible");
271			return (vk::VkImageType)0;
272	}
273}
274
275vk::VkImageLayout getImageLayoutForDescriptorType (vk::VkDescriptorType descType)
276{
277	if (descType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
278		return vk::VK_IMAGE_LAYOUT_GENERAL;
279	else
280		return vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
281}
282
283deUint32 getTextureLevelPyramidDataSize (const tcu::TextureLevelPyramid& srcImage)
284{
285	deUint32 dataSize = 0;
286	for (int level = 0; level < srcImage.getNumLevels(); ++level)
287	{
288		const tcu::ConstPixelBufferAccess srcAccess = srcImage.getLevel(level);
289
290		// tightly packed
291		DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
292
293		dataSize += srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
294	}
295	return dataSize;
296}
297
298void writeTextureLevelPyramidData (void* dst, deUint32 dstLen, const tcu::TextureLevelPyramid& srcImage, vk::VkImageViewType viewType, std::vector<vk::VkBufferImageCopy>* copySlices)
299{
300	// \note cube is copied face-by-face
301	const deUint32	arraySize	= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (srcImage.getLevel(0).getHeight()) :
302								  (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (srcImage.getLevel(0).getDepth()) :
303								  (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)														? (1) :
304								  (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (srcImage.getLevel(0).getDepth()) :
305								  ((deUint32)0);
306	deUint32		levelOffset	= 0;
307
308	DE_ASSERT(arraySize != 0);
309
310	for (int level = 0; level < srcImage.getNumLevels(); ++level)
311	{
312		const tcu::ConstPixelBufferAccess	srcAccess		= srcImage.getLevel(level);
313		const tcu::PixelBufferAccess		dstAccess		(srcAccess.getFormat(), srcAccess.getSize(), srcAccess.getPitch(), (deUint8*)dst + levelOffset);
314		const deUint32						dataSize		= srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
315		const deUint32						sliceDataSize	= dataSize / arraySize;
316		const deInt32						sliceHeight		= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1) : (srcAccess.getHeight());
317		const deInt32						sliceDepth		= (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (srcAccess.getDepth()) : (1);
318		const tcu::IVec3					sliceSize		(srcAccess.getWidth(), sliceHeight, sliceDepth);
319
320		// tightly packed
321		DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
322
323		for (int sliceNdx = 0; sliceNdx < (int)arraySize; ++sliceNdx)
324		{
325			const vk::VkBufferImageCopy copySlice =
326			{
327				(vk::VkDeviceSize)levelOffset + sliceNdx * sliceDataSize,	// bufferOffset
328				(deUint32)sliceSize.x(),									// bufferRowLength
329				(deUint32)sliceSize.y(),									// bufferImageHeight
330				{
331					vk::VK_IMAGE_ASPECT_COLOR_BIT,		// aspectMask
332					(deUint32)level,					// mipLevel
333					(deUint32)sliceNdx,					// arrayLayer
334					1u,									// arraySize
335				},															// imageSubresource
336				{
337					0,
338					0,
339					0,
340				},															// imageOffset
341				{
342					(deUint32)sliceSize.x(),
343					(deUint32)sliceSize.y(),
344					(deUint32)sliceSize.z(),
345				}															// imageExtent
346			};
347			copySlices->push_back(copySlice);
348		}
349
350		DE_ASSERT(arraySize * sliceDataSize == dataSize);
351
352		tcu::copy(dstAccess, srcAccess);
353		levelOffset += dataSize;
354	}
355
356	DE_ASSERT(dstLen == levelOffset);
357	DE_UNREF(dstLen);
358}
359
360de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkBuffer buffer, vk::MemoryRequirement requirement)
361{
362	const vk::VkMemoryRequirements	requirements	= vk::getBufferMemoryRequirements(vki, device, buffer);
363	de::MovePtr<vk::Allocation>		allocation		= allocator.allocate(requirements, requirement);
364
365	VK_CHECK(vki.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset()));
366	return allocation;
367}
368
369de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkImage image, vk::MemoryRequirement requirement)
370{
371	const vk::VkMemoryRequirements	requirements	= vk::getImageMemoryRequirements(vki, device, image);
372	de::MovePtr<vk::Allocation>		allocation		= allocator.allocate(requirements, requirement);
373
374	VK_CHECK(vki.bindImageMemory(device, image, allocation->getMemory(), allocation->getOffset()));
375	return allocation;
376}
377
378vk::VkDescriptorImageInfo makeDescriptorImageInfo (vk::VkSampler sampler)
379{
380	return vk::makeDescriptorImageInfo(sampler, (vk::VkImageView)0, (vk::VkImageLayout)0);
381}
382
383vk::VkDescriptorImageInfo makeDescriptorImageInfo (vk::VkImageView imageView, vk::VkImageLayout layout)
384{
385	return vk::makeDescriptorImageInfo((vk::VkSampler)0, imageView, layout);
386}
387
388void drawQuadrantReferenceResult (const tcu::PixelBufferAccess& dst, const tcu::Vec4& c1, const tcu::Vec4& c2, const tcu::Vec4& c3, const tcu::Vec4& c4)
389{
390	tcu::clear(tcu::getSubregion(dst, 0,					0,						dst.getWidth() / 2,						dst.getHeight() / 2),					c1);
391	tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2,	0,						dst.getWidth() - dst.getWidth() / 2,	dst.getHeight() / 2),					c2);
392	tcu::clear(tcu::getSubregion(dst, 0,					dst.getHeight() / 2,	dst.getWidth() / 2,						dst.getHeight() - dst.getHeight() / 2),	c3);
393	tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2,	dst.getHeight() / 2,	dst.getWidth() - dst.getWidth() / 2,	dst.getHeight() - dst.getHeight() / 2),	c4);
394}
395
396static const vk::VkDescriptorUpdateTemplateEntry createTemplateBinding (deUint32 binding, deUint32 arrayElement, deUint32 descriptorCount, vk::VkDescriptorType descriptorType, size_t offset, size_t stride)
397{
398	const vk::VkDescriptorUpdateTemplateEntry updateBinding =
399	{
400		binding,
401		arrayElement,
402		descriptorCount,
403		descriptorType,
404		offset,
405		stride
406	};
407
408	return updateBinding;
409}
410
411class RawUpdateRegistry
412{
413public:
414							RawUpdateRegistry		(void);
415
416	template<typename Type>
417	void					addWriteObject			(const Type& updateObject);
418	size_t					getWriteObjectOffset	(const deUint32 objectId);
419	const deUint8*			getRawPointer			() const;
420
421private:
422
423	std::vector<deUint8>	m_updateEntries;
424	std::vector<size_t>		m_updateEntryOffsets;
425	size_t					m_nextOffset;
426};
427
428RawUpdateRegistry::RawUpdateRegistry (void)
429	: m_updateEntries()
430	, m_updateEntryOffsets()
431	, m_nextOffset(0)
432{
433}
434
435template<typename Type>
436void RawUpdateRegistry::addWriteObject (const Type& updateObject)
437{
438	m_updateEntryOffsets.push_back(m_nextOffset);
439
440	// in this case, elements <=> bytes
441	m_updateEntries.resize(m_nextOffset + sizeof(updateObject));
442	Type* t = reinterpret_cast<Type*>(m_updateEntries.data() + m_nextOffset);
443	*t = updateObject;
444	m_nextOffset += sizeof(updateObject);
445}
446
447size_t RawUpdateRegistry::getWriteObjectOffset (const deUint32 objectId)
448{
449	return m_updateEntryOffsets[objectId];
450}
451
452const deUint8* RawUpdateRegistry::getRawPointer () const
453{
454	return m_updateEntries.data();
455}
456
457class SingleTargetRenderInstance : public vkt::TestInstance
458{
459public:
460											SingleTargetRenderInstance	(Context&						context,
461																		 const tcu::UVec2&				size);
462
463private:
464	static vk::Move<vk::VkImage>			createColorAttachment		(const vk::DeviceInterface&		vki,
465																		 vk::VkDevice					device,
466																		 vk::Allocator&					allocator,
467																		 const tcu::TextureFormat&		format,
468																		 const tcu::UVec2&				size,
469																		 de::MovePtr<vk::Allocation>*	outAllocation);
470
471	static vk::Move<vk::VkImageView>		createColorAttachmentView	(const vk::DeviceInterface&	vki,
472																		 vk::VkDevice				device,
473																		 const tcu::TextureFormat&	format,
474																		 vk::VkImage				image);
475
476	static vk::Move<vk::VkRenderPass>		createRenderPass			(const vk::DeviceInterface&	vki,
477																		 vk::VkDevice				device,
478																		 const tcu::TextureFormat&	format);
479
480	static vk::Move<vk::VkFramebuffer>		createFramebuffer			(const vk::DeviceInterface&	vki,
481																		 vk::VkDevice				device,
482																		 vk::VkRenderPass			renderpass,
483																		 vk::VkImageView			colorAttachmentView,
484																		 const tcu::UVec2&			size);
485
486	static vk::Move<vk::VkCommandPool>		createCommandPool			(const vk::DeviceInterface&	vki,
487																		 vk::VkDevice				device,
488																		 deUint32					queueFamilyIndex);
489
490	virtual void							logTestPlan					(void) const = 0;
491	virtual void							renderToTarget				(void) = 0;
492	virtual tcu::TestStatus					verifyResultImage			(const tcu::ConstPixelBufferAccess& result) const = 0;
493
494	void									readRenderTarget			(tcu::TextureLevel& dst);
495	tcu::TestStatus							iterate						(void);
496
497protected:
498	const tcu::TextureFormat				m_targetFormat;
499	const tcu::UVec2						m_targetSize;
500
501	const vk::DeviceInterface&				m_vki;
502	const vk::VkDevice						m_device;
503	const vk::VkQueue						m_queue;
504	const deUint32							m_queueFamilyIndex;
505	vk::Allocator&							m_allocator;
506	de::MovePtr<vk::Allocation>				m_colorAttachmentMemory;
507	const vk::Unique<vk::VkImage>			m_colorAttachmentImage;
508	const vk::Unique<vk::VkImageView>		m_colorAttachmentView;
509	const vk::Unique<vk::VkRenderPass>		m_renderPass;
510	const vk::Unique<vk::VkFramebuffer>		m_framebuffer;
511	const vk::Unique<vk::VkCommandPool>		m_cmdPool;
512
513	bool									m_firstIteration;
514};
515
516SingleTargetRenderInstance::SingleTargetRenderInstance (Context&							context,
517														const tcu::UVec2&					size)
518	: vkt::TestInstance			(context)
519	, m_targetFormat			(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
520	, m_targetSize				(size)
521	, m_vki						(context.getDeviceInterface())
522	, m_device					(context.getDevice())
523	, m_queue					(context.getUniversalQueue())
524	, m_queueFamilyIndex		(context.getUniversalQueueFamilyIndex())
525	, m_allocator				(context.getDefaultAllocator())
526	, m_colorAttachmentMemory	(DE_NULL)
527	, m_colorAttachmentImage	(createColorAttachment(m_vki, m_device, m_allocator, m_targetFormat, m_targetSize, &m_colorAttachmentMemory))
528	, m_colorAttachmentView		(createColorAttachmentView(m_vki, m_device, m_targetFormat, *m_colorAttachmentImage))
529	, m_renderPass				(createRenderPass(m_vki, m_device, m_targetFormat))
530	, m_framebuffer				(createFramebuffer(m_vki, m_device, *m_renderPass, *m_colorAttachmentView, m_targetSize))
531	, m_cmdPool					(createCommandPool(m_vki, m_device, context.getUniversalQueueFamilyIndex()))
532	, m_firstIteration			(true)
533{
534}
535
536vk::Move<vk::VkImage> SingleTargetRenderInstance::createColorAttachment (const vk::DeviceInterface&		vki,
537																		 vk::VkDevice					device,
538																		 vk::Allocator&					allocator,
539																		 const tcu::TextureFormat&		format,
540																		 const tcu::UVec2&				size,
541																		 de::MovePtr<vk::Allocation>*	outAllocation)
542{
543	const vk::VkImageCreateInfo	imageInfo	=
544	{
545		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
546		DE_NULL,
547		(vk::VkImageCreateFlags)0,
548		vk::VK_IMAGE_TYPE_2D,							// imageType
549		vk::mapTextureFormat(format),					// format
550		{ size.x(), size.y(), 1u },						// extent
551		1,												// mipLevels
552		1,												// arraySize
553		vk::VK_SAMPLE_COUNT_1_BIT,						// samples
554		vk::VK_IMAGE_TILING_OPTIMAL,					// tiling
555		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT,	// usage
556		vk::VK_SHARING_MODE_EXCLUSIVE,					// sharingMode
557		0u,												// queueFamilyCount
558		DE_NULL,										// pQueueFamilyIndices
559		vk::VK_IMAGE_LAYOUT_UNDEFINED,					// initialLayout
560	};
561
562	vk::Move<vk::VkImage>		image		(vk::createImage(vki, device, &imageInfo));
563	de::MovePtr<vk::Allocation>	allocation	(allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any));
564
565	*outAllocation = allocation;
566	return image;
567}
568
569vk::Move<vk::VkImageView> SingleTargetRenderInstance::createColorAttachmentView (const vk::DeviceInterface&	vki,
570																				 vk::VkDevice				device,
571																				 const tcu::TextureFormat&	format,
572																				 vk::VkImage				image)
573{
574	const vk::VkImageViewCreateInfo createInfo =
575	{
576		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
577		DE_NULL,
578		(vk::VkImageViewCreateFlags)0,
579		image,							// image
580		vk::VK_IMAGE_VIEW_TYPE_2D,		// viewType
581		vk::mapTextureFormat(format),	// format
582		vk::makeComponentMappingRGBA(),
583		{
584			vk::VK_IMAGE_ASPECT_COLOR_BIT,	// aspectMask
585			0u,								// baseMipLevel
586			1u,								// mipLevels
587			0u,								// baseArrayLayer
588			1u,								// arraySize
589		},
590	};
591
592	return vk::createImageView(vki, device, &createInfo);
593}
594
595vk::Move<vk::VkRenderPass> SingleTargetRenderInstance::createRenderPass (const vk::DeviceInterface&		vki,
596																		 vk::VkDevice					device,
597																		 const tcu::TextureFormat&		format)
598{
599	const vk::VkAttachmentDescription	attachmentDescription	=
600	{
601		(vk::VkAttachmentDescriptionFlags)0,
602		vk::mapTextureFormat(format),					// format
603		vk::VK_SAMPLE_COUNT_1_BIT,						// samples
604		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				// loadOp
605		vk::VK_ATTACHMENT_STORE_OP_STORE,				// storeOp
606		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// stencilLoadOp
607		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			// stencilStoreOp
608		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// initialLayout
609		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// finalLayout
610	};
611	const vk::VkAttachmentReference		colorAttachment			=
612	{
613		0u,												// attachment
614		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// layout
615	};
616	const vk::VkAttachmentReference		depthStencilAttachment	=
617	{
618		VK_ATTACHMENT_UNUSED,							// attachment
619		vk::VK_IMAGE_LAYOUT_UNDEFINED					// layout
620	};
621	const vk::VkSubpassDescription		subpass					=
622	{
623		(vk::VkSubpassDescriptionFlags)0,
624		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,			// pipelineBindPoint
625		0u,												// inputAttachmentCount
626		DE_NULL,										// pInputAttachments
627		1u,												// colorAttachmentCount
628		&colorAttachment,								// pColorAttachments
629		DE_NULL,										// pResolveAttachments
630		&depthStencilAttachment,						// pDepthStencilAttachment
631		0u,												// preserveAttachmentCount
632		DE_NULL											// pPreserveAttachments
633	};
634	const vk::VkRenderPassCreateInfo	renderPassCreateInfo	=
635	{
636		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
637		DE_NULL,
638		(vk::VkRenderPassCreateFlags)0,
639		1u,												// attachmentCount
640		&attachmentDescription,							// pAttachments
641		1u,												// subpassCount
642		&subpass,										// pSubpasses
643		0u,												// dependencyCount
644		DE_NULL,										// pDependencies
645	};
646
647	return vk::createRenderPass(vki, device, &renderPassCreateInfo);
648}
649
650vk::Move<vk::VkFramebuffer> SingleTargetRenderInstance::createFramebuffer (const vk::DeviceInterface&	vki,
651																		   vk::VkDevice					device,
652																		   vk::VkRenderPass				renderpass,
653																		   vk::VkImageView				colorAttachmentView,
654																		   const tcu::UVec2&			size)
655{
656	const vk::VkFramebufferCreateInfo	framebufferCreateInfo	=
657	{
658		vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
659		DE_NULL,
660		(vk::VkFramebufferCreateFlags)0,
661		renderpass,				// renderPass
662		1u,						// attachmentCount
663		&colorAttachmentView,	// pAttachments
664		size.x(),				// width
665		size.y(),				// height
666		1,						// layers
667	};
668
669	return vk::createFramebuffer(vki, device, &framebufferCreateInfo);
670}
671
672vk::Move<vk::VkCommandPool> SingleTargetRenderInstance::createCommandPool (const vk::DeviceInterface&	vki,
673																		   vk::VkDevice					device,
674																		   deUint32						queueFamilyIndex)
675{
676	return vk::createCommandPool(vki, device, vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
677}
678
679void SingleTargetRenderInstance::readRenderTarget (tcu::TextureLevel& dst)
680{
681	const deUint64							pixelDataSize				= (deUint64)(m_targetSize.x() * m_targetSize.y() * m_targetFormat.getPixelSize());
682	const vk::VkBufferCreateInfo			bufferCreateInfo			=
683	{
684		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
685		DE_NULL,
686		0u,												// flags
687		pixelDataSize,									// size
688		vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// usage
689		vk::VK_SHARING_MODE_EXCLUSIVE,					// sharingMode
690		0u,												// queueFamilyCount
691		DE_NULL,										// pQueueFamilyIndices
692	};
693	const vk::Unique<vk::VkBuffer>			buffer						(vk::createBuffer(m_vki, m_device, &bufferCreateInfo));
694	const vk::VkImageSubresourceRange		fullSubrange				=
695	{
696		vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
697		0u,												// baseMipLevel
698		1u,												// mipLevels
699		0u,												// baseArraySlice
700		1u,												// arraySize
701	};
702	const vk::VkImageMemoryBarrier			imageBarrier				=
703	{
704		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
705		DE_NULL,
706		vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// srcAccessMask
707		vk::VK_ACCESS_TRANSFER_READ_BIT,				// dstAccessMask
708		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// oldLayout
709		vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// newLayout
710		VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
711		VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
712		*m_colorAttachmentImage,						// image
713		fullSubrange,									// subresourceRange
714	};
715	const vk::VkBufferMemoryBarrier			memoryBarrier				=
716	{
717		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
718		DE_NULL,
719		vk::VK_ACCESS_TRANSFER_WRITE_BIT,				// srcAccessMask
720		vk::VK_ACCESS_HOST_READ_BIT,					// dstAccessMask
721		VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
722		VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
723		*buffer,										// buffer
724		0u,												// offset
725		(vk::VkDeviceSize)pixelDataSize					// size
726	};
727	const vk::VkCommandBufferBeginInfo		cmdBufBeginInfo				=
728	{
729		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
730		DE_NULL,
731		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
732		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
733	};
734	const vk::VkImageSubresourceLayers		firstSlice					=
735	{
736		vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspect
737		0,												// mipLevel
738		0,												// arrayLayer
739		1,												// arraySize
740	};
741	const vk::VkBufferImageCopy				copyRegion					=
742	{
743		0u,												// bufferOffset
744		m_targetSize.x(),								// bufferRowLength
745		m_targetSize.y(),								// bufferImageHeight
746		firstSlice,										// imageSubresource
747		{ 0, 0, 0 },									// imageOffset
748		{ m_targetSize.x(), m_targetSize.y(), 1u }		// imageExtent
749	};
750
751	const de::MovePtr<vk::Allocation>		bufferMemory				= allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible);
752
753	const vk::Unique<vk::VkCommandBuffer>	cmd							(vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
754	const vk::Unique<vk::VkFence>			cmdCompleteFence			(vk::createFence(m_vki, m_device));
755	const deUint64							infiniteTimeout				= ~(deUint64)0u;
756
757	// copy content to buffer
758	VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
759	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0,
760							 0, (const vk::VkMemoryBarrier*)DE_NULL,
761							 0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
762							 1, &imageBarrier);
763	m_vki.cmdCopyImageToBuffer(*cmd, *m_colorAttachmentImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *buffer, 1, &copyRegion);
764	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
765							 0, (const vk::VkMemoryBarrier*)DE_NULL,
766							 1, &memoryBarrier,
767							 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
768	VK_CHECK(m_vki.endCommandBuffer(*cmd));
769
770	// wait for transfer to complete
771	{
772		const vk::VkSubmitInfo	submitInfo	=
773		{
774			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
775			DE_NULL,
776			0u,
777			(const vk::VkSemaphore*)0,
778			(const vk::VkPipelineStageFlags*)DE_NULL,
779			1u,
780			&cmd.get(),
781			0u,
782			(const vk::VkSemaphore*)0,
783		};
784
785		VK_CHECK(m_vki.queueSubmit(m_queue, 1, &submitInfo, *cmdCompleteFence));
786	}
787	VK_CHECK(m_vki.waitForFences(m_device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
788
789	dst.setStorage(m_targetFormat, m_targetSize.x(), m_targetSize.y());
790
791	// copy data
792	invalidateMappedMemoryRange(m_vki, m_device, bufferMemory->getMemory(), bufferMemory->getOffset(), pixelDataSize);
793	tcu::copy(dst, tcu::ConstPixelBufferAccess(dst.getFormat(), dst.getSize(), bufferMemory->getHostPtr()));
794}
795
796tcu::TestStatus SingleTargetRenderInstance::iterate (void)
797{
798	tcu::TextureLevel resultImage;
799
800	// log
801	if (m_firstIteration)
802	{
803		logTestPlan();
804		m_firstIteration = false;
805	}
806
807	// render
808	{
809		// transition to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
810		const vk::VkImageSubresourceRange		fullSubrange				=
811		{
812			vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
813			0u,												// baseMipLevel
814			1u,												// mipLevels
815			0u,												// baseArraySlice
816			1u,												// arraySize
817		};
818		const vk::VkImageMemoryBarrier			imageBarrier				=
819		{
820			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
821			DE_NULL,
822			0u,												// srcAccessMask
823			vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// dstAccessMask
824			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// oldLayout
825			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// newLayout
826			VK_QUEUE_FAMILY_IGNORED,						// srcQueueFamilyIndex
827			VK_QUEUE_FAMILY_IGNORED,						// destQueueFamilyIndex
828			*m_colorAttachmentImage,						// image
829			fullSubrange,									// subresourceRange
830		};
831		const vk::VkCommandBufferBeginInfo		cmdBufBeginInfo				=
832		{
833			vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
834			DE_NULL,
835			vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
836			(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
837		};
838
839		const vk::Unique<vk::VkCommandBuffer>	cmd					(vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
840		const vk::Unique<vk::VkFence>			fence				(vk::createFence(m_vki, m_device));
841		const deUint64							infiniteTimeout		= ~(deUint64)0u;
842
843		VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
844		m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
845								 0, (const vk::VkMemoryBarrier*)DE_NULL,
846								 0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
847								 1, &imageBarrier);
848		VK_CHECK(m_vki.endCommandBuffer(*cmd));
849
850		{
851			const vk::VkSubmitInfo	submitInfo	=
852			{
853				vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
854				DE_NULL,
855				0u,
856				(const vk::VkSemaphore*)0,
857				(const vk::VkPipelineStageFlags*)DE_NULL,
858				1u,
859				&cmd.get(),
860				0u,
861				(const vk::VkSemaphore*)0,
862			};
863
864			VK_CHECK(m_vki.queueSubmit(m_queue, 1u, &submitInfo, *fence));
865		}
866		VK_CHECK(m_vki.waitForFences(m_device, 1u, &fence.get(), VK_TRUE, infiniteTimeout));
867
868		// and then render to
869		renderToTarget();
870	}
871
872	// read and verify
873	readRenderTarget(resultImage);
874	return verifyResultImage(resultImage.getAccess());
875}
876
877class RenderInstanceShaders
878{
879public:
880														RenderInstanceShaders		(const vk::DeviceInterface&				vki,
881																					 vk::VkDevice							device,
882																					 const vk::VkPhysicalDeviceFeatures&	deviceFeatures,
883																					 const vk::BinaryCollection&			programCollection);
884
885	inline bool											hasTessellationStage		(void) const { return *m_tessCtrlShaderModule != 0 || *m_tessEvalShaderModule != 0;	}
886	inline deUint32										getNumStages				(void) const { return (deUint32)m_stageInfos.size();								}
887	inline const vk::VkPipelineShaderStageCreateInfo*	getStages					(void) const { return &m_stageInfos[0];												}
888
889private:
890	void												addStage					(const vk::DeviceInterface&				vki,
891																					 vk::VkDevice							device,
892																					 const vk::VkPhysicalDeviceFeatures&	deviceFeatures,
893																					 const vk::BinaryCollection&			programCollection,
894																					 const char*							name,
895																					 vk::VkShaderStageFlagBits				stage,
896																					 vk::Move<vk::VkShaderModule>*			outModule);
897
898	vk::VkPipelineShaderStageCreateInfo					getShaderStageCreateInfo	(vk::VkShaderStageFlagBits stage, vk::VkShaderModule shader) const;
899
900	vk::Move<vk::VkShaderModule>						m_vertexShaderModule;
901	vk::Move<vk::VkShaderModule>						m_tessCtrlShaderModule;
902	vk::Move<vk::VkShaderModule>						m_tessEvalShaderModule;
903	vk::Move<vk::VkShaderModule>						m_geometryShaderModule;
904	vk::Move<vk::VkShaderModule>						m_fragmentShaderModule;
905	std::vector<vk::VkPipelineShaderStageCreateInfo>	m_stageInfos;
906};
907
908RenderInstanceShaders::RenderInstanceShaders (const vk::DeviceInterface&			vki,
909											  vk::VkDevice							device,
910											  const vk::VkPhysicalDeviceFeatures&	deviceFeatures,
911											  const vk::BinaryCollection&			programCollection)
912{
913	addStage(vki, device, deviceFeatures, programCollection, "vertex",		vk::VK_SHADER_STAGE_VERTEX_BIT,						&m_vertexShaderModule);
914	addStage(vki, device, deviceFeatures, programCollection, "tess_ctrl",	vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,		&m_tessCtrlShaderModule);
915	addStage(vki, device, deviceFeatures, programCollection, "tess_eval",	vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,	&m_tessEvalShaderModule);
916	addStage(vki, device, deviceFeatures, programCollection, "geometry",	vk::VK_SHADER_STAGE_GEOMETRY_BIT,					&m_geometryShaderModule);
917	addStage(vki, device, deviceFeatures, programCollection, "fragment",	vk::VK_SHADER_STAGE_FRAGMENT_BIT,					&m_fragmentShaderModule);
918
919	DE_ASSERT(!m_stageInfos.empty());
920}
921
922void RenderInstanceShaders::addStage (const vk::DeviceInterface&			vki,
923									  vk::VkDevice							device,
924									  const vk::VkPhysicalDeviceFeatures&	deviceFeatures,
925									  const vk::BinaryCollection&			programCollection,
926									  const char*							name,
927									  vk::VkShaderStageFlagBits				stage,
928									  vk::Move<vk::VkShaderModule>*			outModule)
929{
930	if (programCollection.contains(name))
931	{
932		if (vk::isShaderStageSupported(deviceFeatures, stage))
933		{
934			vk::Move<vk::VkShaderModule>	module	= createShaderModule(vki, device, programCollection.get(name), (vk::VkShaderModuleCreateFlags)0);
935
936			m_stageInfos.push_back(getShaderStageCreateInfo(stage, *module));
937			*outModule = module;
938		}
939		else
940		{
941			// Wait for the GPU to idle so that throwing the exception
942			// below doesn't free in-use GPU resource.
943			vki.deviceWaitIdle(device);
944			TCU_THROW(NotSupportedError, (de::toString(stage) + " is not supported").c_str());
945		}
946	}
947}
948
949vk::VkPipelineShaderStageCreateInfo RenderInstanceShaders::getShaderStageCreateInfo (vk::VkShaderStageFlagBits stage, vk::VkShaderModule shader) const
950{
951	const vk::VkPipelineShaderStageCreateInfo	stageCreateInfo	=
952	{
953		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
954		DE_NULL,
955		(vk::VkPipelineShaderStageCreateFlags)0,
956		stage,			// stage
957		shader,			// shader
958		"main",
959		DE_NULL,		// pSpecializationInfo
960	};
961	return stageCreateInfo;
962}
963
964class SingleCmdRenderInstance : public SingleTargetRenderInstance
965{
966public:
967									SingleCmdRenderInstance	(Context&						context,
968															 bool							isPrimaryCmdBuf,
969															 const tcu::UVec2&				renderSize);
970
971private:
972	vk::Move<vk::VkPipeline>		createPipeline				(vk::VkPipelineLayout pipelineLayout);
973
974	virtual vk::VkPipelineLayout	getPipelineLayout			(void) const = 0;
975	virtual void					writeDrawCmdBuffer			(vk::VkCommandBuffer cmd) const = 0;
976
977	void							renderToTarget				(void);
978
979	const bool						m_isPrimaryCmdBuf;
980};
981
982SingleCmdRenderInstance::SingleCmdRenderInstance (Context&			context,
983												  bool				isPrimaryCmdBuf,
984												  const tcu::UVec2&	renderSize)
985	: SingleTargetRenderInstance	(context, renderSize)
986	, m_isPrimaryCmdBuf				(isPrimaryCmdBuf)
987{
988}
989
990vk::Move<vk::VkPipeline> SingleCmdRenderInstance::createPipeline (vk::VkPipelineLayout pipelineLayout)
991{
992	const RenderInstanceShaders							shaderStages		(m_vki, m_device, m_context.getDeviceFeatures(), m_context.getBinaryCollection());
993	const vk::VkPrimitiveTopology						topology			= shaderStages.hasTessellationStage() ? vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
994	const vk::VkPipelineVertexInputStateCreateInfo		vertexInputState	=
995	{
996		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
997		DE_NULL,
998		(vk::VkPipelineVertexInputStateCreateFlags)0,
999		0u,											// bindingCount
1000		DE_NULL,									// pVertexBindingDescriptions
1001		0u,											// attributeCount
1002		DE_NULL,									// pVertexAttributeDescriptions
1003	};
1004	const vk::VkPipelineInputAssemblyStateCreateInfo	iaState				=
1005	{
1006		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1007		DE_NULL,
1008		(vk::VkPipelineInputAssemblyStateCreateFlags)0,
1009		topology,									// topology
1010		VK_FALSE,									// primitiveRestartEnable
1011	};
1012	const vk::VkPipelineTessellationStateCreateInfo		tessState			=
1013	{
1014		vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
1015		DE_NULL,
1016		(vk::VkPipelineTessellationStateCreateFlags)0,
1017		3u,											// patchControlPoints
1018	};
1019	const vk::VkViewport								viewport			=
1020	{
1021		0.0f,										// originX
1022		0.0f,										// originY
1023		float(m_targetSize.x()),					// width
1024		float(m_targetSize.y()),					// height
1025		0.0f,										// minDepth
1026		1.0f,										// maxDepth
1027	};
1028	const vk::VkRect2D									renderArea			=
1029	{
1030		{ 0, 0 },									// offset
1031		{ m_targetSize.x(), m_targetSize.y() },		// extent
1032	};
1033	const vk::VkPipelineViewportStateCreateInfo			vpState				=
1034	{
1035		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
1036		DE_NULL,
1037		(vk::VkPipelineViewportStateCreateFlags)0,
1038		1u,											// viewportCount
1039		&viewport,
1040		1u,
1041		&renderArea,
1042	};
1043	const vk::VkPipelineRasterizationStateCreateInfo	rsState				=
1044	{
1045		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1046		DE_NULL,
1047		(vk::VkPipelineRasterizationStateCreateFlags)0,
1048		VK_TRUE,									// depthClipEnable
1049		VK_FALSE,									// rasterizerDiscardEnable
1050		vk::VK_POLYGON_MODE_FILL,					// fillMode
1051		vk::VK_CULL_MODE_NONE,						// cullMode
1052		vk::VK_FRONT_FACE_COUNTER_CLOCKWISE,		// frontFace
1053		VK_FALSE,									// depthBiasEnable
1054		0.0f,										// depthBias
1055		0.0f,										// depthBiasClamp
1056		0.0f,										// slopeScaledDepthBias
1057		1.0f,										// lineWidth
1058	};
1059	const vk::VkSampleMask								sampleMask			= 0x01u;
1060	const vk::VkPipelineMultisampleStateCreateInfo		msState				=
1061	{
1062		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1063		DE_NULL,
1064		(vk::VkPipelineMultisampleStateCreateFlags)0,
1065		vk::VK_SAMPLE_COUNT_1_BIT,					// rasterSamples
1066		VK_FALSE,									// sampleShadingEnable
1067		0.0f,										// minSampleShading
1068		&sampleMask,								// sampleMask
1069		VK_FALSE,									// alphaToCoverageEnable
1070		VK_FALSE,									// alphaToOneEnable
1071	};
1072	const vk::VkPipelineDepthStencilStateCreateInfo		dsState				=
1073	{
1074		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
1075		DE_NULL,
1076		(vk::VkPipelineDepthStencilStateCreateFlags)0,
1077		VK_FALSE,									// depthTestEnable
1078		VK_FALSE,									// depthWriteEnable
1079		vk::VK_COMPARE_OP_ALWAYS,					// depthCompareOp
1080		VK_FALSE,									// depthBoundsTestEnable
1081		VK_FALSE,									// stencilTestEnable
1082		{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },	// front
1083		{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u },	// back
1084		-1.0f,										// minDepthBounds
1085		+1.0f,										// maxDepthBounds
1086	};
1087	const vk::VkPipelineColorBlendAttachmentState		cbAttachment		=
1088	{
1089		VK_FALSE,									// blendEnable
1090		vk::VK_BLEND_FACTOR_ZERO,					// srcBlendColor
1091		vk::VK_BLEND_FACTOR_ZERO,					// destBlendColor
1092		vk::VK_BLEND_OP_ADD,						// blendOpColor
1093		vk::VK_BLEND_FACTOR_ZERO,					// srcBlendAlpha
1094		vk::VK_BLEND_FACTOR_ZERO,					// destBlendAlpha
1095		vk::VK_BLEND_OP_ADD,						// blendOpAlpha
1096		(vk::VK_COLOR_COMPONENT_R_BIT |
1097		 vk::VK_COLOR_COMPONENT_G_BIT |
1098		 vk::VK_COLOR_COMPONENT_B_BIT |
1099		 vk::VK_COLOR_COMPONENT_A_BIT),				// channelWriteMask
1100	};
1101	const vk::VkPipelineColorBlendStateCreateInfo		cbState				=
1102	{
1103		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1104		DE_NULL,
1105		(vk::VkPipelineColorBlendStateCreateFlags)0,
1106		VK_FALSE,									// logicOpEnable
1107		vk::VK_LOGIC_OP_CLEAR,						// logicOp
1108		1u,											// attachmentCount
1109		&cbAttachment,								// pAttachments
1110		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConst
1111	};
1112	const vk::VkGraphicsPipelineCreateInfo createInfo =
1113	{
1114		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1115		DE_NULL,
1116		(vk::VkPipelineCreateFlags)0,
1117		shaderStages.getNumStages(),									// stageCount
1118		shaderStages.getStages(),										// pStages
1119		&vertexInputState,												// pVertexInputState
1120		&iaState,														// pInputAssemblyState
1121		(shaderStages.hasTessellationStage() ? &tessState : DE_NULL),	// pTessellationState
1122		&vpState,														// pViewportState
1123		&rsState,														// pRasterState
1124		&msState,														// pMultisampleState
1125		&dsState,														// pDepthStencilState
1126		&cbState,														// pColorBlendState
1127		(const vk::VkPipelineDynamicStateCreateInfo*)DE_NULL,			// pDynamicState
1128		pipelineLayout,													// layout
1129		*m_renderPass,													// renderPass
1130		0u,																// subpass
1131		(vk::VkPipeline)0,												// basePipelineHandle
1132		0u,																// basePipelineIndex
1133	};
1134	return createGraphicsPipeline(m_vki, m_device, (vk::VkPipelineCache)0u, &createInfo);
1135}
1136
1137void SingleCmdRenderInstance::renderToTarget (void)
1138{
1139	const vk::VkRect2D									renderArea						=
1140	{
1141		{ 0, 0 },								// offset
1142		{ m_targetSize.x(), m_targetSize.y() },	// extent
1143	};
1144	const vk::VkCommandBufferBeginInfo					mainCmdBufBeginInfo				=
1145	{
1146		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1147		DE_NULL,
1148		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
1149		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
1150	};
1151	const vk::VkCommandBufferInheritanceInfo			passCmdBufInheritInfo			=
1152	{
1153		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
1154		DE_NULL,
1155		(vk::VkRenderPass)*m_renderPass,						// renderPass
1156		0u,														// subpass
1157		(vk::VkFramebuffer)*m_framebuffer,						// framebuffer
1158		VK_FALSE,												// occlusionQueryEnable
1159		(vk::VkQueryControlFlags)0,
1160		(vk::VkQueryPipelineStatisticFlags)0,
1161	};
1162	const vk::VkCommandBufferBeginInfo					passCmdBufBeginInfo				=
1163	{
1164		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1165		DE_NULL,
1166		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT |
1167		vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,	// flags
1168		&passCmdBufInheritInfo,
1169	};
1170	const vk::VkClearValue								clearValue					= vk::makeClearValueColorF32(0.0f, 0.0f, 0.0f, 0.0f);
1171	const vk::VkRenderPassBeginInfo						renderPassBeginInfo			=
1172	{
1173		vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1174		DE_NULL,
1175		*m_renderPass,		// renderPass
1176		*m_framebuffer,		// framebuffer
1177		renderArea,			// renderArea
1178		1u,					// clearValueCount
1179		&clearValue,		// pClearValues
1180	};
1181
1182	const vk::VkPipelineLayout							pipelineLayout				(getPipelineLayout());
1183	const vk::Unique<vk::VkPipeline>					pipeline					(createPipeline(pipelineLayout));
1184	const vk::Unique<vk::VkCommandBuffer>				mainCmd						(vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1185	const vk::Unique<vk::VkCommandBuffer>				passCmd						((m_isPrimaryCmdBuf) ? (vk::Move<vk::VkCommandBuffer>()) : (vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY)));
1186	const vk::Unique<vk::VkFence>						fence						(vk::createFence(m_vki, m_device));
1187	const deUint64										infiniteTimeout				= ~(deUint64)0u;
1188	const vk::VkSubpassContents							passContents				= (m_isPrimaryCmdBuf) ? (vk::VK_SUBPASS_CONTENTS_INLINE) : (vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
1189
1190	VK_CHECK(m_vki.beginCommandBuffer(*mainCmd, &mainCmdBufBeginInfo));
1191	m_vki.cmdBeginRenderPass(*mainCmd, &renderPassBeginInfo, passContents);
1192
1193	if (m_isPrimaryCmdBuf)
1194	{
1195		m_vki.cmdBindPipeline(*mainCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1196		writeDrawCmdBuffer(*mainCmd);
1197	}
1198	else
1199	{
1200		VK_CHECK(m_vki.beginCommandBuffer(*passCmd, &passCmdBufBeginInfo));
1201		m_vki.cmdBindPipeline(*passCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1202		writeDrawCmdBuffer(*passCmd);
1203		VK_CHECK(m_vki.endCommandBuffer(*passCmd));
1204
1205		m_vki.cmdExecuteCommands(*mainCmd, 1, &passCmd.get());
1206	}
1207
1208	m_vki.cmdEndRenderPass(*mainCmd);
1209	VK_CHECK(m_vki.endCommandBuffer(*mainCmd));
1210
1211	// submit and wait for them to finish before exiting scope. (Killing in-flight objects is a no-no).
1212	{
1213		const vk::VkSubmitInfo	submitInfo	=
1214		{
1215			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1216			DE_NULL,
1217			0u,
1218			(const vk::VkSemaphore*)0,
1219			(const vk::VkPipelineStageFlags*)DE_NULL,
1220			1u,
1221			&mainCmd.get(),
1222			0u,
1223			(const vk::VkSemaphore*)0,
1224		};
1225		VK_CHECK(m_vki.queueSubmit(m_queue, 1, &submitInfo, *fence));
1226	}
1227	VK_CHECK(m_vki.waitForFences(m_device, 1, &fence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
1228}
1229
1230enum ShaderInputInterface
1231{
1232	SHADER_INPUT_SINGLE_DESCRIPTOR = 0,					//!< one descriptor
1233	SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS,		//!< multiple descriptors with contiguous binding id's
1234	SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS,	//!< multiple descriptors with discontiguous binding id's
1235	SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS,		//!< multiple descriptors with large gaps between binding id's
1236	SHADER_INPUT_DESCRIPTOR_ARRAY,						//!< descriptor array
1237
1238	SHADER_INPUT_LAST
1239};
1240
1241deUint32 getInterfaceNumResources (ShaderInputInterface shaderInterface)
1242{
1243	switch (shaderInterface)
1244	{
1245		case SHADER_INPUT_SINGLE_DESCRIPTOR:					return 1u;
1246		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:		return 2u;
1247		case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:	return 2u;
1248		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:		return 2u;
1249		case SHADER_INPUT_DESCRIPTOR_ARRAY:						return 2u;
1250
1251		default:
1252			DE_FATAL("Impossible");
1253			return 0u;
1254	}
1255}
1256
1257class BufferRenderInstance : public SingleCmdRenderInstance
1258{
1259public:
1260													BufferRenderInstance			(Context&										context,
1261																					 DescriptorUpdateMethod							updateMethod,
1262																					 bool											isPrimaryCmdBuf,
1263																					 vk::VkDescriptorType							descriptorType,
1264																					 vk::VkShaderStageFlags							stageFlags,
1265																					 ShaderInputInterface							shaderInterface,
1266																					 bool											viewOffset,
1267																					 bool											dynamicOffset,
1268																					 bool											dynamicOffsetNonZero);
1269
1270	static vk::Move<vk::VkBuffer>					createSourceBuffer				(const vk::DeviceInterface&						vki,
1271																					 vk::VkDevice									device,
1272																					 vk::Allocator&									allocator,
1273																					 vk::VkDescriptorType							descriptorType,
1274																					 deUint32										offset,
1275																					 deUint32										bufferSize,
1276																					 de::MovePtr<vk::Allocation>*					outMemory);
1277
1278	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool			(const vk::DeviceInterface&						vki,
1279																					 vk::VkDevice									device,
1280																					 vk::VkDescriptorType							descriptorType,
1281																					 ShaderInputInterface							shaderInterface);
1282
1283	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout		(const vk::DeviceInterface&						vki,
1284																					 vk::VkDevice									device,
1285																					 vk::VkDescriptorType							descriptorType,
1286																					 ShaderInputInterface							shaderInterface,
1287																					 vk::VkShaderStageFlags							stageFlags,
1288																					 DescriptorUpdateMethod							updateMethod);
1289
1290	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet				(const vk::DeviceInterface&						vki,
1291																					 DescriptorUpdateMethod							updateMethod,
1292																					 vk::VkDevice									device,
1293																					 vk::VkDescriptorSetLayout						descriptorSetLayout,
1294																					 vk::VkDescriptorPool							descriptorPool,
1295																					 vk::VkDescriptorType							descriptorType,
1296																					 ShaderInputInterface							shaderInterface,
1297																					 vk::VkBuffer									sourceBufferA,
1298																					 const deUint32									viewOffsetA,
1299																					 vk::VkBuffer									sourceBufferB,
1300																					 const deUint32									viewOffsetB,
1301																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
1302																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
1303																					 RawUpdateRegistry&								updateRegistry,
1304																					 vk::VkPipelineLayout							pipelineLayout = DE_NULL);
1305
1306	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout			(const vk::DeviceInterface&						vki,
1307																					 vk::VkDevice									device,
1308																					 vk::VkDescriptorSetLayout						descriptorSetLayout);
1309
1310	static void										writeDescriptorSet				(const vk::DeviceInterface&						vki,
1311																					 vk::VkDevice									device,
1312																					 vk::VkDescriptorSetLayout						descriptorSetLayout,
1313																					 vk::VkDescriptorPool							descriptorPool,
1314																					 vk::VkDescriptorType							descriptorType,
1315																					 ShaderInputInterface							shaderInterface,
1316																					 vk::VkBuffer									sourceBufferA,
1317																					 const deUint32									viewOffsetA,
1318																					 vk::VkBuffer									sourceBufferB,
1319																					 const deUint32									viewOffsetB,
1320																					 vk::VkDescriptorSet							descriptorSet,
1321																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
1322																					 DescriptorUpdateMethod							updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
1323
1324	static void										writeDescriptorSetWithTemplate	(const vk::DeviceInterface&						vki,
1325																					 vk::VkDevice									device,
1326																					 vk::VkDescriptorSetLayout						descriptorSetLayout,
1327																					 vk::VkDescriptorPool							descriptorPool,
1328																					 vk::VkDescriptorType							descriptorType,
1329																					 ShaderInputInterface							shaderInterface,
1330																					 vk::VkBuffer									sourceBufferA,
1331																					 const deUint32									viewOffsetA,
1332																					 vk::VkBuffer									sourceBufferB,
1333																					 const deUint32									viewOffsetB,
1334																					 vk::VkDescriptorSet							descriptorSet,
1335																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
1336																					 RawUpdateRegistry&								updateRegistry,
1337																					 bool											withPush = false,
1338																					 vk::VkPipelineLayout							pipelineLayout = 0);
1339
1340	void											logTestPlan						(void) const;
1341	vk::VkPipelineLayout							getPipelineLayout				(void) const;
1342	void											writeDrawCmdBuffer				(vk::VkCommandBuffer cmd) const;
1343	tcu::TestStatus									verifyResultImage				(const tcu::ConstPixelBufferAccess& result) const;
1344
1345	enum
1346	{
1347		RENDER_SIZE				= 128,
1348		BUFFER_DATA_SIZE		= 8 * sizeof(float),
1349		BUFFER_SIZE_A			= 2048, //!< a lot more than required
1350		BUFFER_SIZE_B			= 2560, //!< a lot more than required
1351
1352		STATIC_OFFSET_VALUE_A	= 256,
1353		DYNAMIC_OFFSET_VALUE_A	= 512,
1354		STATIC_OFFSET_VALUE_B	= 1024,
1355		DYNAMIC_OFFSET_VALUE_B	= 768,
1356	};
1357
1358	const DescriptorUpdateMethod					m_updateMethod;
1359	const vk::VkDescriptorType						m_descriptorType;
1360	const ShaderInputInterface						m_shaderInterface;
1361	const bool										m_setViewOffset;
1362	const bool										m_setDynamicOffset;
1363	const bool										m_dynamicOffsetNonZero;
1364	const vk::VkShaderStageFlags					m_stageFlags;
1365
1366	const deUint32									m_viewOffsetA;
1367	const deUint32									m_viewOffsetB;
1368	const deUint32									m_dynamicOffsetA;
1369	const deUint32									m_dynamicOffsetB;
1370	const deUint32									m_effectiveOffsetA;
1371	const deUint32									m_effectiveOffsetB;
1372	const deUint32									m_bufferSizeA;
1373	const deUint32									m_bufferSizeB;
1374
1375	de::MovePtr<vk::Allocation>						m_bufferMemoryA;
1376	de::MovePtr<vk::Allocation>						m_bufferMemoryB;
1377	const vk::Unique<vk::VkBuffer>					m_sourceBufferA;
1378	const vk::Unique<vk::VkBuffer>					m_sourceBufferB;
1379	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
1380	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
1381	RawUpdateRegistry								m_updateRegistry;
1382	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
1383	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
1384	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
1385	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
1386};
1387
1388BufferRenderInstance::BufferRenderInstance	(Context&						context,
1389											 DescriptorUpdateMethod			updateMethod,
1390											 bool							isPrimaryCmdBuf,
1391											 vk::VkDescriptorType			descriptorType,
1392											 vk::VkShaderStageFlags			stageFlags,
1393											 ShaderInputInterface			shaderInterface,
1394											 bool							viewOffset,
1395											 bool							dynamicOffset,
1396											 bool							dynamicOffsetNonZero)
1397	: SingleCmdRenderInstance		(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
1398	, m_updateMethod				(updateMethod)
1399	, m_descriptorType				(descriptorType)
1400	, m_shaderInterface				(shaderInterface)
1401	, m_setViewOffset				(viewOffset)
1402	, m_setDynamicOffset			(dynamicOffset)
1403	, m_dynamicOffsetNonZero		(dynamicOffsetNonZero)
1404	, m_stageFlags					(stageFlags)
1405	, m_viewOffsetA					((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u))
1406	, m_viewOffsetB					((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u))
1407	, m_dynamicOffsetA				((dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_A) : (0u))
1408	, m_dynamicOffsetB				((dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_B) : (0u))
1409	, m_effectiveOffsetA			((isDynamicDescriptorType(m_descriptorType)) ? (m_viewOffsetA + m_dynamicOffsetA) : (m_viewOffsetA))
1410	, m_effectiveOffsetB			((isDynamicDescriptorType(m_descriptorType)) ? (m_viewOffsetB + m_dynamicOffsetB) : (m_viewOffsetB))
1411	, m_bufferSizeA					(BUFFER_SIZE_A)
1412	, m_bufferSizeB					(BUFFER_SIZE_B)
1413	, m_bufferMemoryA				(DE_NULL)
1414	, m_bufferMemoryB				(DE_NULL)
1415	, m_sourceBufferA				(createSourceBuffer(m_vki, m_device, m_allocator, m_descriptorType, m_effectiveOffsetA, m_bufferSizeA, &m_bufferMemoryA))
1416	, m_sourceBufferB				((getInterfaceNumResources(m_shaderInterface) == 1u)
1417										? vk::Move<vk::VkBuffer>()
1418										: createSourceBuffer(m_vki, m_device, m_allocator, m_descriptorType, m_effectiveOffsetB, m_bufferSizeB, &m_bufferMemoryB))
1419	, m_descriptorPool				(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
1420	, m_updateTemplate				()
1421	, m_updateRegistry				()
1422	, m_updateBuilder				()
1423	, m_descriptorSetLayout			(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags, m_updateMethod))
1424	, m_pipelineLayout				(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
1425	, m_descriptorSet				(createDescriptorSet(m_vki, m_updateMethod, m_device, *m_descriptorSetLayout, *m_descriptorPool, m_descriptorType, m_shaderInterface, *m_sourceBufferA, m_viewOffsetA, *m_sourceBufferB, m_viewOffsetB, m_updateBuilder, m_updateTemplate, m_updateRegistry, *m_pipelineLayout))
1426{
1427	if (m_setDynamicOffset)
1428		DE_ASSERT(isDynamicDescriptorType(m_descriptorType));
1429	if (m_dynamicOffsetNonZero)
1430		DE_ASSERT(m_setDynamicOffset);
1431}
1432
1433vk::Move<vk::VkBuffer> BufferRenderInstance::createSourceBuffer (const vk::DeviceInterface&		vki,
1434																 vk::VkDevice					device,
1435																 vk::Allocator&					allocator,
1436																 vk::VkDescriptorType			descriptorType,
1437																 deUint32						offset,
1438																 deUint32						bufferSize,
1439																 de::MovePtr<vk::Allocation>*	outMemory)
1440{
1441	static const float				s_colors[]			=
1442	{
1443		0.0f, 1.0f, 0.0f, 1.0f,		// green
1444		1.0f, 1.0f, 0.0f, 1.0f,		// yellow
1445	};
1446	DE_STATIC_ASSERT(sizeof(s_colors) == BUFFER_DATA_SIZE);
1447	DE_ASSERT(offset + BUFFER_DATA_SIZE <= bufferSize);
1448	DE_ASSERT(offset % sizeof(float) == 0);
1449	DE_ASSERT(bufferSize % sizeof(float) == 0);
1450
1451	const bool						isUniformBuffer		= isUniformDescriptorType(descriptorType);
1452	const vk::VkBufferUsageFlags	usageFlags			= (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1453	const float						preGuardValue		= 0.5f;
1454	const float						postGuardValue		= 0.75f;
1455	const vk::VkBufferCreateInfo	bufferCreateInfo	=
1456	{
1457		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1458		DE_NULL,
1459		0u,								// flags
1460		bufferSize,						// size
1461		usageFlags,						// usage
1462		vk::VK_SHARING_MODE_EXCLUSIVE,	// sharingMode
1463		0u,								// queueFamilyCount
1464		DE_NULL,						// pQueueFamilyIndices
1465	};
1466	vk::Move<vk::VkBuffer>			buffer				(vk::createBuffer(vki, device, &bufferCreateInfo));
1467	de::MovePtr<vk::Allocation>		bufferMemory		= allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible);
1468	void* const						mapPtr				= bufferMemory->getHostPtr();
1469
1470	// guard with interesting values
1471	for (size_t preGuardOffset = 0; preGuardOffset + sizeof(float) <= (size_t)offset; preGuardOffset += sizeof(float))
1472		deMemcpy((deUint8*)mapPtr + preGuardOffset, &preGuardValue, sizeof(float));
1473
1474	deMemcpy((deUint8*)mapPtr + offset, s_colors, sizeof(s_colors));
1475	for (size_t postGuardOffset = (size_t)offset + sizeof(s_colors); postGuardOffset + sizeof(float) <= (size_t)bufferSize; postGuardOffset += sizeof(float))
1476		deMemcpy((deUint8*)mapPtr + postGuardOffset, &postGuardValue, sizeof(float));
1477	deMemset((deUint8*)mapPtr + offset + sizeof(s_colors), 0x5A, (size_t)bufferSize - (size_t)offset - sizeof(s_colors)); // fill with interesting pattern that produces valid floats
1478
1479	flushMappedMemoryRange(vki, device, bufferMemory->getMemory(), bufferMemory->getOffset(), bufferSize);
1480
1481	// Flushed host-visible memory is automatically made available to the GPU, no barrier is needed.
1482
1483	*outMemory = bufferMemory;
1484	return buffer;
1485}
1486
1487vk::Move<vk::VkDescriptorPool> BufferRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
1488																		   vk::VkDevice					device,
1489																		   vk::VkDescriptorType			descriptorType,
1490																		   ShaderInputInterface			shaderInterface)
1491{
1492	return vk::DescriptorPoolBuilder()
1493		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
1494		.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
1495}
1496
1497vk::Move<vk::VkDescriptorSetLayout> BufferRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&	vki,
1498																					 vk::VkDevice				device,
1499																					 vk::VkDescriptorType		descriptorType,
1500																					 ShaderInputInterface		shaderInterface,
1501																					 vk::VkShaderStageFlags		stageFlags,
1502																					 DescriptorUpdateMethod		updateMethod)
1503{
1504	vk::DescriptorSetLayoutBuilder			builder;
1505	vk::VkDescriptorSetLayoutCreateFlags	extraFlags			= 0;
1506
1507	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
1508			updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
1509	{
1510		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
1511	}
1512
1513	switch (shaderInterface)
1514	{
1515		case SHADER_INPUT_SINGLE_DESCRIPTOR:
1516			builder.addSingleBinding(descriptorType, stageFlags);
1517			break;
1518
1519		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
1520			builder.addSingleBinding(descriptorType, stageFlags);
1521			builder.addSingleBinding(descriptorType, stageFlags);
1522			break;
1523
1524		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
1525			builder.addSingleIndexedBinding(descriptorType, stageFlags, 0x7FFEu);
1526			builder.addSingleIndexedBinding(descriptorType, stageFlags, 0xFFFEu);
1527			break;
1528
1529		case SHADER_INPUT_DESCRIPTOR_ARRAY:
1530			builder.addArrayBinding(descriptorType, 2u, stageFlags);
1531			break;
1532
1533		default:
1534			DE_FATAL("Impossible");
1535	}
1536
1537	return builder.build(vki, device, extraFlags);
1538}
1539
1540vk::Move<vk::VkDescriptorSet> BufferRenderInstance::createDescriptorSet (const vk::DeviceInterface&						vki,
1541																		 DescriptorUpdateMethod							updateMethod,
1542																		 vk::VkDevice									device,
1543																		 vk::VkDescriptorSetLayout						descriptorSetLayout,
1544																		 vk::VkDescriptorPool							descriptorPool,
1545																		 vk::VkDescriptorType							descriptorType,
1546																		 ShaderInputInterface							shaderInterface,
1547																		 vk::VkBuffer									bufferA,
1548																		 deUint32										offsetA,
1549																		 vk::VkBuffer									bufferB,
1550																		 deUint32										offsetB,
1551																		 vk::DescriptorSetUpdateBuilder&				updateBuilder,
1552																		 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
1553																		 RawUpdateRegistry&								updateRegistry,
1554																		 vk::VkPipelineLayout							pipelineLayout)
1555{
1556	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
1557	{
1558		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1559		DE_NULL,
1560		descriptorPool,
1561		1u,
1562		&descriptorSetLayout
1563	};
1564
1565	vk::Move<vk::VkDescriptorSet>			descriptorSet;
1566	if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
1567	{
1568		descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
1569	}
1570	else
1571	{
1572		descriptorSet = vk::Move<vk::VkDescriptorSet>();
1573	}
1574
1575	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
1576	{
1577		writeDescriptorSetWithTemplate(vki, device, descriptorSetLayout, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateTemplate, updateRegistry);
1578	}
1579	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
1580	{
1581		writeDescriptorSetWithTemplate(vki, device, descriptorSetLayout, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateTemplate, updateRegistry, true, pipelineLayout);
1582	}
1583	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
1584	{
1585		writeDescriptorSet(vki, device, descriptorSetLayout, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateBuilder, updateMethod);
1586	}
1587	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
1588	{
1589		writeDescriptorSet(vki, device, descriptorSetLayout, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateBuilder);
1590	}
1591
1592	return descriptorSet;
1593}
1594
1595void BufferRenderInstance::writeDescriptorSet (const vk::DeviceInterface&			vki,
1596											   vk::VkDevice							device,
1597											   vk::VkDescriptorSetLayout			descriptorSetLayout,
1598											   vk::VkDescriptorPool					descriptorPool,
1599											   vk::VkDescriptorType					descriptorType,
1600											   ShaderInputInterface					shaderInterface,
1601											   vk::VkBuffer							bufferA,
1602											   const deUint32						offsetA,
1603											   vk::VkBuffer							bufferB,
1604											   const deUint32						offsetB,
1605											   vk::VkDescriptorSet					descriptorSet,
1606											   vk::DescriptorSetUpdateBuilder&		updateBuilder,
1607											   DescriptorUpdateMethod				updateMethod)
1608{
1609	DE_UNREF(descriptorSetLayout);
1610	DE_UNREF(descriptorPool);
1611	const vk::VkDescriptorBufferInfo		bufferInfos[2]	=
1612	{
1613		vk::makeDescriptorBufferInfo(bufferA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
1614		vk::makeDescriptorBufferInfo(bufferB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
1615	};
1616
1617	switch (shaderInterface)
1618	{
1619		case SHADER_INPUT_SINGLE_DESCRIPTOR:
1620			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
1621			break;
1622
1623		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
1624			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
1625			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &bufferInfos[1]);
1626			break;
1627
1628		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
1629			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0x7FFEu), descriptorType, &bufferInfos[0]);
1630			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0xFFFEu), descriptorType, &bufferInfos[1]);
1631			break;
1632
1633		case SHADER_INPUT_DESCRIPTOR_ARRAY:
1634			updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, bufferInfos);
1635			break;
1636
1637		default:
1638			DE_FATAL("Impossible");
1639	}
1640
1641	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
1642	{
1643		updateBuilder.update(vki, device);
1644	}
1645}
1646
1647void BufferRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface&						vki,
1648														   vk::VkDevice										device,
1649														   vk::VkDescriptorSetLayout						layout,
1650														   vk::VkDescriptorPool								descriptorPool,
1651														   vk::VkDescriptorType								descriptorType,
1652														   ShaderInputInterface								shaderInterface,
1653														   vk::VkBuffer										bufferA,
1654														   const deUint32									offsetA,
1655														   vk::VkBuffer										bufferB,
1656														   const deUint32									offsetB,
1657														   vk::VkDescriptorSet								descriptorSet,
1658														   vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
1659														   RawUpdateRegistry&								updateRegistry,
1660														   bool												withPush,
1661														   vk::VkPipelineLayout								pipelineLayout)
1662{
1663	DE_UNREF(descriptorPool);
1664	const vk::VkDescriptorBufferInfo						bufferInfos[2]	=
1665	{
1666		vk::makeDescriptorBufferInfo(bufferA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
1667		vk::makeDescriptorBufferInfo(bufferB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
1668	};
1669	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
1670	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
1671	{
1672		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
1673		DE_NULL,
1674		0,
1675		0,			// descriptorUpdateEntryCount
1676		DE_NULL,	// pDescriptorUpdateEntries
1677		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
1678		layout,
1679		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
1680		pipelineLayout,
1681		0
1682	};
1683	updateRegistry.addWriteObject(bufferInfos[0]);
1684	updateRegistry.addWriteObject(bufferInfos[1]);
1685
1686	switch (shaderInterface)
1687	{
1688		case SHADER_INPUT_SINGLE_DESCRIPTOR:
1689			updateEntries.push_back(createTemplateBinding(0u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
1690			break;
1691
1692		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
1693			updateEntries.push_back(createTemplateBinding(0u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
1694			updateEntries.push_back(createTemplateBinding(1u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
1695			break;
1696
1697		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
1698			updateEntries.push_back(createTemplateBinding(0x7FFEu, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
1699			updateEntries.push_back(createTemplateBinding(0xFFFEu, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
1700			break;
1701
1702		case SHADER_INPUT_DESCRIPTOR_ARRAY:
1703			updateEntries.push_back(createTemplateBinding(0u, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(bufferInfos[0])));
1704			break;
1705
1706		default:
1707			DE_FATAL("Impossible");
1708	}
1709
1710	templateCreateInfo.pDescriptorUpdateEntries			= &updateEntries[0];
1711	templateCreateInfo.descriptorUpdateEntryCount		= (deUint32)updateEntries.size();
1712
1713	updateTemplate										= vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
1714
1715	if (!withPush)
1716	{
1717		vki.updateDescriptorSetWithTemplate(device, descriptorSet, *updateTemplate, updateRegistry.getRawPointer());
1718	}
1719}
1720
1721vk::Move<vk::VkPipelineLayout> BufferRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
1722																		   vk::VkDevice					device,
1723																		   vk::VkDescriptorSetLayout	descriptorSetLayout)
1724{
1725	const vk::VkPipelineLayoutCreateInfo createInfo =
1726	{
1727		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1728		DE_NULL,
1729		(vk::VkPipelineLayoutCreateFlags)0,
1730		1,						// descriptorSetCount
1731		&descriptorSetLayout,	// pSetLayouts
1732		0u,						// pushConstantRangeCount
1733		DE_NULL,				// pPushConstantRanges
1734	};
1735
1736	return vk::createPipelineLayout(vki, device, &createInfo);
1737}
1738
1739void BufferRenderInstance::logTestPlan (void) const
1740{
1741	std::ostringstream msg;
1742
1743	msg << "Rendering 2x2 yellow-green grid.\n"
1744		<< "Single descriptor set. Descriptor set contains "
1745			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
1746			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
1747			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
1748			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
1749			    (const char*)DE_NULL)
1750		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
1751		<< "Buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
1752
1753	if (isDynamicDescriptorType(m_descriptorType))
1754	{
1755		if (m_setDynamicOffset)
1756		{
1757			msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
1758				<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
1759		}
1760		else
1761		{
1762			msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
1763		}
1764	}
1765
1766	if (m_stageFlags == 0u)
1767	{
1768		msg << "Descriptors are not accessed in any shader stage.\n";
1769	}
1770	else
1771	{
1772		msg << "Descriptors are accessed in {"
1773			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)					? (" vertex")			: (""))
1774			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
1775			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
1776			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)				? (" geometry")			: (""))
1777			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)				? (" fragment")			: (""))
1778			<< " } stages.\n";
1779	}
1780
1781	m_context.getTestContext().getLog()
1782		<< tcu::TestLog::Message
1783		<< msg.str()
1784		<< tcu::TestLog::EndMessage;
1785}
1786
1787vk::VkPipelineLayout BufferRenderInstance::getPipelineLayout (void) const
1788{
1789	return *m_pipelineLayout;
1790}
1791
1792void BufferRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
1793{
1794	// \note dynamic offset replaces the view offset, i.e. it is not offset relative to the view offset
1795	const deUint32						dynamicOffsets[]	=
1796	{
1797		m_dynamicOffsetA,
1798		m_dynamicOffsetB,
1799	};
1800	const deUint32						numOffsets			= (!m_setDynamicOffset) ? (0u) : (getInterfaceNumResources(m_shaderInterface));
1801	const deUint32* const				dynamicOffsetPtr	= (!m_setDynamicOffset) ? (DE_NULL) : (dynamicOffsets);
1802
1803	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
1804	{
1805		m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), numOffsets, dynamicOffsetPtr);
1806	}
1807	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
1808	{
1809		m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, *m_updateTemplate, getPipelineLayout(), 0, (const void*)m_updateRegistry.getRawPointer());
1810	}
1811	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
1812	{
1813		m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0);
1814	}
1815
1816	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
1817}
1818
1819tcu::TestStatus BufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
1820{
1821	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
1822	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
1823	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
1824
1825	drawQuadrantReferenceResult(reference.getAccess(), yellow, green, green, yellow);
1826
1827	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
1828		return tcu::TestStatus::fail("Image verification failed");
1829	else
1830		return tcu::TestStatus::pass("Pass");
1831}
1832
1833class ComputeInstanceResultBuffer
1834{
1835public:
1836	enum
1837	{
1838		DATA_SIZE = sizeof(tcu::Vec4[4])
1839	};
1840
1841											ComputeInstanceResultBuffer	(const vk::DeviceInterface&		vki,
1842																		 vk::VkDevice					device,
1843																		 vk::Allocator&					allocator);
1844
1845	void									readResultContentsTo		(tcu::Vec4 (*results)[4]) const;
1846
1847	inline vk::VkBuffer						getBuffer					(void) const { return *m_buffer;			}
1848	inline const vk::VkBufferMemoryBarrier*	getResultReadBarrier		(void) const { return &m_bufferBarrier;		}
1849
1850private:
1851	static vk::Move<vk::VkBuffer>			createResultBuffer			(const vk::DeviceInterface&		vki,
1852																		 vk::VkDevice					device,
1853																		 vk::Allocator&					allocator,
1854																		 de::MovePtr<vk::Allocation>*	outAllocation);
1855
1856	static vk::VkBufferMemoryBarrier		createResultBufferBarrier	(vk::VkBuffer buffer);
1857
1858	const vk::DeviceInterface&				m_vki;
1859	const vk::VkDevice						m_device;
1860
1861	de::MovePtr<vk::Allocation>				m_bufferMem;
1862	const vk::Unique<vk::VkBuffer>			m_buffer;
1863	const vk::VkBufferMemoryBarrier			m_bufferBarrier;
1864};
1865
1866ComputeInstanceResultBuffer::ComputeInstanceResultBuffer (const vk::DeviceInterface&	vki,
1867														  vk::VkDevice					device,
1868														  vk::Allocator&				allocator)
1869	: m_vki				(vki)
1870	, m_device			(device)
1871	, m_bufferMem		(DE_NULL)
1872	, m_buffer			(createResultBuffer(m_vki, m_device, allocator, &m_bufferMem))
1873	, m_bufferBarrier	(createResultBufferBarrier(*m_buffer))
1874{
1875}
1876
1877void ComputeInstanceResultBuffer::readResultContentsTo (tcu::Vec4 (*results)[4]) const
1878{
1879	invalidateMappedMemoryRange(m_vki, m_device, m_bufferMem->getMemory(), m_bufferMem->getOffset(), sizeof(*results));
1880	deMemcpy(*results, m_bufferMem->getHostPtr(), sizeof(*results));
1881}
1882
1883vk::Move<vk::VkBuffer> ComputeInstanceResultBuffer::createResultBuffer (const vk::DeviceInterface&		vki,
1884																		vk::VkDevice					device,
1885																		vk::Allocator&					allocator,
1886																		de::MovePtr<vk::Allocation>*	outAllocation)
1887{
1888	const vk::VkBufferCreateInfo	createInfo	=
1889	{
1890		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1891		DE_NULL,
1892		0u,											// flags
1893		(vk::VkDeviceSize)DATA_SIZE,				// size
1894		vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// usage
1895		vk::VK_SHARING_MODE_EXCLUSIVE,				// sharingMode
1896		0u,											// queueFamilyCount
1897		DE_NULL,									// pQueueFamilyIndices
1898	};
1899	vk::Move<vk::VkBuffer>			buffer		(vk::createBuffer(vki, device, &createInfo));
1900	de::MovePtr<vk::Allocation>		allocation	(allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
1901	const float						clearValue	= -1.0f;
1902	void*							mapPtr		= allocation->getHostPtr();
1903
1904	for (size_t offset = 0; offset < DATA_SIZE; offset += sizeof(float))
1905		deMemcpy(((deUint8*)mapPtr) + offset, &clearValue, sizeof(float));
1906
1907	flushMappedMemoryRange(vki, device, allocation->getMemory(), allocation->getOffset(), (vk::VkDeviceSize)DATA_SIZE);
1908
1909	*outAllocation = allocation;
1910	return buffer;
1911}
1912
1913vk::VkBufferMemoryBarrier ComputeInstanceResultBuffer::createResultBufferBarrier (vk::VkBuffer buffer)
1914{
1915	const vk::VkBufferMemoryBarrier bufferBarrier =
1916	{
1917		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
1918		DE_NULL,
1919		vk::VK_ACCESS_SHADER_WRITE_BIT,				// outputMask
1920		vk::VK_ACCESS_HOST_READ_BIT,				// inputMask
1921		VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
1922		VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
1923		buffer,										// buffer
1924		(vk::VkDeviceSize)0u,						// offset
1925		DATA_SIZE,									// size
1926	};
1927	return bufferBarrier;
1928}
1929
1930class ComputePipeline
1931{
1932public:
1933											ComputePipeline			(const vk::DeviceInterface&			vki,
1934																	 vk::VkDevice						device,
1935																	 const vk::BinaryCollection&		programCollection,
1936																	 deUint32							numDescriptorSets,
1937																	 const vk::VkDescriptorSetLayout*	descriptorSetLayouts);
1938
1939	inline vk::VkPipeline					getPipeline				(void) const { return *m_pipeline;			};
1940	inline vk::VkPipelineLayout				getPipelineLayout		(void) const { return *m_pipelineLayout;	};
1941
1942private:
1943	static vk::Move<vk::VkPipelineLayout>	createPipelineLayout	(const vk::DeviceInterface&			vki,
1944																	 vk::VkDevice						device,
1945																	 deUint32							numDescriptorSets,
1946																	 const vk::VkDescriptorSetLayout*	descriptorSetLayouts);
1947
1948	static vk::Move<vk::VkPipeline>			createPipeline			(const vk::DeviceInterface&			vki,
1949																	 vk::VkDevice						device,
1950																	 const vk::BinaryCollection&		programCollection,
1951																	 vk::VkPipelineLayout				layout);
1952
1953	const vk::Unique<vk::VkPipelineLayout>	m_pipelineLayout;
1954	const vk::Unique<vk::VkPipeline>		m_pipeline;
1955};
1956
1957ComputePipeline::ComputePipeline (const vk::DeviceInterface&		vki,
1958								  vk::VkDevice						device,
1959								  const vk::BinaryCollection&		programCollection,
1960								  deUint32							numDescriptorSets,
1961								  const vk::VkDescriptorSetLayout*	descriptorSetLayouts)
1962	: m_pipelineLayout	(createPipelineLayout(vki, device, numDescriptorSets, descriptorSetLayouts))
1963	, m_pipeline		(createPipeline(vki, device, programCollection, *m_pipelineLayout))
1964{
1965}
1966
1967vk::Move<vk::VkPipelineLayout> ComputePipeline::createPipelineLayout (const vk::DeviceInterface&		vki,
1968																	  vk::VkDevice						device,
1969																	  deUint32							numDescriptorSets,
1970																	  const vk::VkDescriptorSetLayout*	descriptorSetLayouts)
1971{
1972	const vk::VkPipelineLayoutCreateInfo createInfo =
1973	{
1974		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1975		DE_NULL,
1976		(vk::VkPipelineLayoutCreateFlags)0,
1977		numDescriptorSets,		// descriptorSetCount
1978		descriptorSetLayouts,	// pSetLayouts
1979		0u,						// pushConstantRangeCount
1980		DE_NULL,				// pPushConstantRanges
1981	};
1982	return vk::createPipelineLayout(vki, device, &createInfo);
1983}
1984
1985vk::Move<vk::VkPipeline> ComputePipeline::createPipeline (const vk::DeviceInterface&	vki,
1986														  vk::VkDevice					device,
1987														  const vk::BinaryCollection&	programCollection,
1988														  vk::VkPipelineLayout			layout)
1989{
1990	const vk::Unique<vk::VkShaderModule>		computeModule		(vk::createShaderModule(vki, device, programCollection.get("compute"), (vk::VkShaderModuleCreateFlags)0u));
1991	const vk::VkPipelineShaderStageCreateInfo	cs					=
1992	{
1993		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
1994		DE_NULL,
1995		(vk::VkPipelineShaderStageCreateFlags)0,
1996		vk::VK_SHADER_STAGE_COMPUTE_BIT,	// stage
1997		*computeModule,						// shader
1998		"main",
1999		DE_NULL,							// pSpecializationInfo
2000	};
2001	const vk::VkComputePipelineCreateInfo		createInfo			=
2002	{
2003		vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
2004		DE_NULL,
2005		0u,								// flags
2006		cs,								// cs
2007		layout,							// layout
2008		(vk::VkPipeline)0,				// basePipelineHandle
2009		0u,								// basePipelineIndex
2010	};
2011	return createComputePipeline(vki, device, (vk::VkPipelineCache)0u, &createInfo);
2012}
2013
2014class ComputeCommand
2015{
2016public:
2017											ComputeCommand	(const vk::DeviceInterface&			vki,
2018															 vk::VkDevice						device,
2019															 vk::VkPipeline						pipeline,
2020															 vk::VkPipelineLayout				pipelineLayout,
2021															 const tcu::UVec3&					numWorkGroups,
2022															 int								numDescriptorSets,
2023															 const vk::VkDescriptorSet*			descriptorSets,
2024															 int								numDynamicOffsets,
2025															 const deUint32*					dynamicOffsets,
2026															 int								numPreBarriers,
2027															 const vk::VkBufferMemoryBarrier*	preBarriers,
2028															 int								numPostBarriers,
2029															 const vk::VkBufferMemoryBarrier*	postBarriers);
2030
2031	void									submitAndWait	(deUint32 queueFamilyIndex, vk::VkQueue queue, vk::VkDescriptorUpdateTemplate updateTemplate = DE_NULL, const void *rawUpdateData = 0) const;
2032	void									submitAndWait	(deUint32 queueFamilyIndex, vk::VkQueue queue, vk::DescriptorSetUpdateBuilder& updateBuilder) const;
2033
2034private:
2035	const vk::DeviceInterface&				m_vki;
2036	const vk::VkDevice						m_device;
2037	const vk::VkPipeline					m_pipeline;
2038	const vk::VkPipelineLayout				m_pipelineLayout;
2039	const tcu::UVec3						m_numWorkGroups;
2040	const int								m_numDescriptorSets;
2041	const vk::VkDescriptorSet* const		m_descriptorSets;
2042	const int								m_numDynamicOffsets;
2043	const deUint32* const					m_dynamicOffsets;
2044	const int								m_numPreBarriers;
2045	const vk::VkBufferMemoryBarrier* const	m_preBarriers;
2046	const int								m_numPostBarriers;
2047	const vk::VkBufferMemoryBarrier* const	m_postBarriers;
2048};
2049
2050ComputeCommand::ComputeCommand (const vk::DeviceInterface&			vki,
2051								vk::VkDevice						device,
2052								vk::VkPipeline						pipeline,
2053								vk::VkPipelineLayout				pipelineLayout,
2054								const tcu::UVec3&					numWorkGroups,
2055								int									numDescriptorSets,
2056								const vk::VkDescriptorSet*			descriptorSets,
2057								int									numDynamicOffsets,
2058								const deUint32*						dynamicOffsets,
2059								int									numPreBarriers,
2060								const vk::VkBufferMemoryBarrier*	preBarriers,
2061								int									numPostBarriers,
2062								const vk::VkBufferMemoryBarrier*	postBarriers)
2063	: m_vki					(vki)
2064	, m_device				(device)
2065	, m_pipeline			(pipeline)
2066	, m_pipelineLayout		(pipelineLayout)
2067	, m_numWorkGroups		(numWorkGroups)
2068	, m_numDescriptorSets	(numDescriptorSets)
2069	, m_descriptorSets		(descriptorSets)
2070	, m_numDynamicOffsets	(numDynamicOffsets)
2071	, m_dynamicOffsets		(dynamicOffsets)
2072	, m_numPreBarriers		(numPreBarriers)
2073	, m_preBarriers			(preBarriers)
2074	, m_numPostBarriers		(numPostBarriers)
2075	, m_postBarriers		(postBarriers)
2076{
2077}
2078
2079void ComputeCommand::submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, vk::VkDescriptorUpdateTemplate updateTemplate, const void *rawUpdateData) const
2080{
2081	const vk::VkCommandPoolCreateInfo				cmdPoolCreateInfo	=
2082	{
2083		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
2084		DE_NULL,
2085		vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// flags
2086		queueFamilyIndex,									// queueFamilyIndex
2087	};
2088	const vk::Unique<vk::VkCommandPool>				cmdPool				(vk::createCommandPool(m_vki, m_device, &cmdPoolCreateInfo));
2089
2090	const vk::VkFenceCreateInfo						fenceCreateInfo		=
2091	{
2092		vk::VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
2093		DE_NULL,
2094		0u,			// flags
2095	};
2096
2097	const vk::VkCommandBufferAllocateInfo			cmdBufCreateInfo	=
2098	{
2099		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
2100		DE_NULL,
2101		*cmdPool,											// cmdPool
2102		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,				// level
2103		1u,													// count
2104	};
2105	const vk::VkCommandBufferBeginInfo				cmdBufBeginInfo		=
2106	{
2107		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2108		DE_NULL,
2109		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
2110		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
2111	};
2112
2113	const vk::Unique<vk::VkFence>					cmdCompleteFence	(vk::createFence(m_vki, m_device, &fenceCreateInfo));
2114	const vk::Unique<vk::VkCommandBuffer>			cmd					(vk::allocateCommandBuffer(m_vki, m_device, &cmdBufCreateInfo));
2115	const deUint64									infiniteTimeout		= ~(deUint64)0u;
2116
2117	VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
2118
2119	m_vki.cmdBindPipeline(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline);
2120
2121	if (m_numDescriptorSets)
2122	{
2123		m_vki.cmdBindDescriptorSets(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, m_numDescriptorSets, m_descriptorSets, m_numDynamicOffsets, m_dynamicOffsets);
2124	}
2125
2126	if (updateTemplate != DE_NULL)
2127	{
2128		// we need to update the push descriptors
2129		m_vki.cmdPushDescriptorSetWithTemplateKHR(*cmd, updateTemplate, m_pipelineLayout, 0, rawUpdateData);
2130	}
2131
2132	if (m_numPreBarriers)
2133		m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0,
2134								 0, (const vk::VkMemoryBarrier*)DE_NULL,
2135								 m_numPreBarriers, m_preBarriers,
2136								 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
2137
2138	m_vki.cmdDispatch(*cmd, m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
2139	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
2140							 0, (const vk::VkMemoryBarrier*)DE_NULL,
2141							 m_numPostBarriers, m_postBarriers,
2142							 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
2143	VK_CHECK(m_vki.endCommandBuffer(*cmd));
2144
2145	// run
2146	{
2147		const vk::VkSubmitInfo	submitInfo	=
2148		{
2149			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
2150			DE_NULL,
2151			0u,
2152			(const vk::VkSemaphore*)0,
2153			(const vk::VkPipelineStageFlags*)DE_NULL,
2154			1u,
2155			&cmd.get(),
2156			0u,
2157			(const vk::VkSemaphore*)0,
2158		};
2159		VK_CHECK(m_vki.queueSubmit(queue, 1, &submitInfo, *cmdCompleteFence));
2160	}
2161	VK_CHECK(m_vki.waitForFences(m_device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
2162}
2163
2164//cmdPushDescriptorSet variant
2165void ComputeCommand::submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, vk::DescriptorSetUpdateBuilder& updateBuilder) const
2166{
2167	const vk::VkCommandPoolCreateInfo				cmdPoolCreateInfo	=
2168	{
2169		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
2170		DE_NULL,
2171		vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// flags
2172		queueFamilyIndex,									// queueFamilyIndex
2173	};
2174	const vk::Unique<vk::VkCommandPool>				cmdPool				(vk::createCommandPool(m_vki, m_device, &cmdPoolCreateInfo));
2175	const vk::VkCommandBufferBeginInfo				cmdBufBeginInfo		=
2176	{
2177		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2178		DE_NULL,
2179		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
2180		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
2181	};
2182
2183	const vk::Unique<vk::VkFence>					cmdCompleteFence	(vk::createFence(m_vki, m_device));
2184	const vk::Unique<vk::VkCommandBuffer>			cmd					(vk::allocateCommandBuffer(m_vki, m_device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2185	const deUint64									infiniteTimeout		= ~(deUint64)0u;
2186
2187	VK_CHECK(m_vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
2188
2189	m_vki.cmdBindPipeline(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline);
2190
2191	if (m_numDescriptorSets)
2192	{
2193		m_vki.cmdBindDescriptorSets(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, m_numDescriptorSets, m_descriptorSets, m_numDynamicOffsets, m_dynamicOffsets);
2194	}
2195
2196	updateBuilder.updateWithPush(m_vki, *cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0);
2197
2198	if (m_numPreBarriers)
2199		m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0,
2200								 0, (const vk::VkMemoryBarrier*)DE_NULL,
2201								 m_numPreBarriers, m_preBarriers,
2202								 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
2203
2204	m_vki.cmdDispatch(*cmd, m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
2205	m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
2206							 0, (const vk::VkMemoryBarrier*)DE_NULL,
2207							 m_numPostBarriers, m_postBarriers,
2208							 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
2209	VK_CHECK(m_vki.endCommandBuffer(*cmd));
2210
2211	// run
2212	{
2213		const vk::VkSubmitInfo	submitInfo	=
2214		{
2215			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
2216			DE_NULL,
2217			0u,
2218			(const vk::VkSemaphore*)0,
2219			(const vk::VkPipelineStageFlags*)DE_NULL,
2220			1u,
2221			&cmd.get(),
2222			0u,
2223			(const vk::VkSemaphore*)0,
2224		};
2225		VK_CHECK(m_vki.queueSubmit(queue, 1, &submitInfo, *cmdCompleteFence));
2226	}
2227	VK_CHECK(m_vki.waitForFences(m_device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
2228}
2229
2230class BufferComputeInstance : public vkt::TestInstance
2231{
2232public:
2233											BufferComputeInstance				(Context&						context,
2234																				 DescriptorUpdateMethod			updateMethod,
2235																				 vk::VkDescriptorType			descriptorType,
2236																				 ShaderInputInterface			shaderInterface,
2237																				 bool							viewOffset,
2238																				 bool							dynamicOffset,
2239																				 bool							dynamicOffsetNonZero);
2240
2241private:
2242	vk::Move<vk::VkBuffer>					createColorDataBuffer				(deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation);
2243	vk::Move<vk::VkBufferView>				createBufferView					(vk::VkBuffer buffer, deUint32 offset) const;
2244	vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout			(void) const;
2245	vk::Move<vk::VkDescriptorPool>			createDescriptorPool				(void) const;
2246	vk::Move<vk::VkDescriptorSet>			createDescriptorSet					(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf);
2247	void									writeDescriptorSet					(vk::VkDescriptorSet descriptorSet, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf);
2248	void									writeDescriptorSetWithTemplate		(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
2249
2250	tcu::TestStatus							iterate								(void);
2251	void									logTestPlan							(void) const;
2252	tcu::TestStatus							testResourceAccess					(void);
2253
2254	enum
2255	{
2256		STATIC_OFFSET_VALUE_A	= 256,
2257		DYNAMIC_OFFSET_VALUE_A	= 512,
2258		STATIC_OFFSET_VALUE_B	= 1024,
2259		DYNAMIC_OFFSET_VALUE_B	= 768,
2260	};
2261
2262	const DescriptorUpdateMethod					m_updateMethod;
2263	const vk::VkDescriptorType						m_descriptorType;
2264	const ShaderInputInterface						m_shaderInterface;
2265	const bool										m_setViewOffset;
2266	const bool										m_setDynamicOffset;
2267	const bool										m_dynamicOffsetNonZero;
2268
2269	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
2270	const vk::DeviceInterface&						m_vki;
2271	const vk::VkDevice								m_device;
2272	const vk::VkQueue								m_queue;
2273	const deUint32									m_queueFamilyIndex;
2274	vk::Allocator&									m_allocator;
2275
2276	const ComputeInstanceResultBuffer				m_result;
2277
2278	RawUpdateRegistry								m_updateRegistry;
2279	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
2280};
2281
2282BufferComputeInstance::BufferComputeInstance (Context&						context,
2283											  DescriptorUpdateMethod		updateMethod,
2284											  vk::VkDescriptorType			descriptorType,
2285											  ShaderInputInterface			shaderInterface,
2286											  bool							viewOffset,
2287											  bool							dynamicOffset,
2288											  bool							dynamicOffsetNonZero)
2289	: vkt::TestInstance			(context)
2290	, m_updateMethod			(updateMethod)
2291	, m_descriptorType			(descriptorType)
2292	, m_shaderInterface			(shaderInterface)
2293	, m_setViewOffset			(viewOffset)
2294	, m_setDynamicOffset		(dynamicOffset)
2295	, m_dynamicOffsetNonZero	(dynamicOffsetNonZero)
2296	, m_updateTemplate			()
2297	, m_vki						(context.getDeviceInterface())
2298	, m_device					(context.getDevice())
2299	, m_queue					(context.getUniversalQueue())
2300	, m_queueFamilyIndex		(context.getUniversalQueueFamilyIndex())
2301	, m_allocator				(context.getDefaultAllocator())
2302	, m_result					(m_vki, m_device, m_allocator)
2303	, m_updateRegistry			()
2304	, m_updateBuilder			()
2305{
2306	if (m_dynamicOffsetNonZero)
2307		DE_ASSERT(m_setDynamicOffset);
2308}
2309
2310vk::Move<vk::VkBuffer> BufferComputeInstance::createColorDataBuffer (deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation)
2311{
2312	DE_ASSERT(offset + sizeof(tcu::Vec4[2]) <= bufferSize);
2313
2314	const bool						isUniformBuffer		= isUniformDescriptorType(m_descriptorType);
2315	const vk::VkBufferUsageFlags	usageFlags			= (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
2316	const vk::VkBufferCreateInfo	createInfo =
2317	{
2318		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
2319		DE_NULL,
2320		0u,								// flags
2321		(vk::VkDeviceSize)bufferSize,	// size
2322		usageFlags,						// usage
2323		vk::VK_SHARING_MODE_EXCLUSIVE,	// sharingMode
2324		0u,								// queueFamilyCount
2325		DE_NULL,						// pQueueFamilyIndices
2326	};
2327	vk::Move<vk::VkBuffer>			buffer				(vk::createBuffer(m_vki, m_device, &createInfo));
2328	de::MovePtr<vk::Allocation>		allocation			(allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible));
2329	void*							mapPtr				= allocation->getHostPtr();
2330
2331	if (offset)
2332		deMemset(mapPtr, 0x5A, (size_t)offset);
2333	deMemcpy((deUint8*)mapPtr + offset, value1.getPtr(), sizeof(tcu::Vec4));
2334	deMemcpy((deUint8*)mapPtr + offset + sizeof(tcu::Vec4), value2.getPtr(), sizeof(tcu::Vec4));
2335	deMemset((deUint8*)mapPtr + offset + 2 * sizeof(tcu::Vec4), 0x5A, (size_t)bufferSize - (size_t)offset - 2 * sizeof(tcu::Vec4));
2336
2337	flushMappedMemoryRange(m_vki, m_device, allocation->getMemory(), allocation->getOffset(), bufferSize);
2338
2339	*outAllocation = allocation;
2340	return buffer;
2341}
2342
2343vk::Move<vk::VkDescriptorSetLayout> BufferComputeInstance::createDescriptorSetLayout (void) const
2344{
2345	vk::DescriptorSetLayoutBuilder			builder;
2346	vk::VkDescriptorSetLayoutCreateFlags	extraFlags = 0;
2347
2348	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
2349			m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
2350	{
2351		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
2352	}
2353
2354	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
2355
2356	switch (m_shaderInterface)
2357	{
2358		case SHADER_INPUT_SINGLE_DESCRIPTOR:
2359			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
2360			break;
2361
2362		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
2363			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
2364			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
2365			break;
2366
2367		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
2368			builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, 0x7FFEu);
2369			builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, 0xFFFEu);
2370			break;
2371
2372		case SHADER_INPUT_DESCRIPTOR_ARRAY:
2373			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
2374			break;
2375
2376		default:
2377			DE_FATAL("Impossible");
2378	};
2379
2380	return builder.build(m_vki, m_device, extraFlags);
2381}
2382
2383vk::Move<vk::VkDescriptorPool> BufferComputeInstance::createDescriptorPool (void) const
2384{
2385	return vk::DescriptorPoolBuilder()
2386		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
2387		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
2388		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
2389}
2390
2391vk::Move<vk::VkDescriptorSet> BufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf)
2392{
2393	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
2394	{
2395		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2396		DE_NULL,
2397		pool,
2398		1u,
2399		&layout
2400	};
2401
2402	vk::Move<vk::VkDescriptorSet>			descriptorSet;
2403	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
2404	{
2405		descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
2406	}
2407	else
2408	{
2409		descriptorSet = vk::Move<vk::VkDescriptorSet>();
2410	}
2411
2412	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
2413	{
2414		writeDescriptorSetWithTemplate(*descriptorSet, layout, viewA, offsetA, viewB, offsetB, resBuf);
2415	}
2416	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
2417	{
2418		writeDescriptorSet(*descriptorSet, viewA, offsetA, viewB, offsetB, resBuf);
2419	}
2420
2421	return descriptorSet;
2422}
2423
2424void BufferComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf)
2425{
2426	const vk::VkDescriptorBufferInfo		resultInfo		= vk::makeDescriptorBufferInfo(resBuf, 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
2427	const vk::VkDescriptorBufferInfo		bufferInfos[2]	=
2428	{
2429		vk::makeDescriptorBufferInfo(viewA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
2430		vk::makeDescriptorBufferInfo(viewB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
2431	};
2432
2433	// result
2434	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
2435
2436	// buffers
2437	switch (m_shaderInterface)
2438	{
2439		case SHADER_INPUT_SINGLE_DESCRIPTOR:
2440			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &bufferInfos[0]);
2441			break;
2442
2443		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
2444			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &bufferInfos[0]);
2445			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &bufferInfos[1]);
2446			break;
2447
2448		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
2449			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0x7FFEu), m_descriptorType, &bufferInfos[0]);
2450			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0xFFFEu), m_descriptorType, &bufferInfos[1]);
2451			break;
2452
2453		case SHADER_INPUT_DESCRIPTOR_ARRAY:
2454			m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, bufferInfos);
2455			break;
2456
2457		default:
2458			DE_FATAL("Impossible");
2459	}
2460
2461	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
2462	{
2463		m_updateBuilder.update(m_vki, m_device);
2464	}
2465}
2466
2467void BufferComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf, bool withPush, vk::VkPipelineLayout pipelineLayout)
2468{
2469	const vk::VkDescriptorBufferInfo						resultInfo			= vk::makeDescriptorBufferInfo(resBuf, 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
2470	const vk::VkDescriptorBufferInfo						bufferInfos[2]		=
2471	{
2472		vk::makeDescriptorBufferInfo(viewA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
2473		vk::makeDescriptorBufferInfo(viewB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
2474	};
2475	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
2476	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
2477	{
2478		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
2479		DE_NULL,
2480		0,
2481		0,			// descriptorUpdateEntryCount
2482		DE_NULL,	// pDescriptorUpdateEntries
2483		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
2484		layout,
2485		vk::VK_PIPELINE_BIND_POINT_COMPUTE,
2486		pipelineLayout,
2487		0
2488	};
2489	m_updateRegistry.addWriteObject(resultInfo);
2490	m_updateRegistry.addWriteObject(bufferInfos[0]);
2491	m_updateRegistry.addWriteObject(bufferInfos[1]);
2492
2493	// result
2494	updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_updateRegistry.getWriteObjectOffset(0), 0));
2495
2496	// buffers
2497	switch (m_shaderInterface)
2498	{
2499		case SHADER_INPUT_SINGLE_DESCRIPTOR:
2500			updateEntries.push_back(createTemplateBinding(1, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
2501			break;
2502
2503		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
2504			updateEntries.push_back(createTemplateBinding(1, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
2505			updateEntries.push_back(createTemplateBinding(2, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(2), 0));
2506			break;
2507
2508		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
2509			updateEntries.push_back(createTemplateBinding(0x7FFEu, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
2510			updateEntries.push_back(createTemplateBinding(0xFFFEu, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(2), 0));
2511			break;
2512
2513		case SHADER_INPUT_DESCRIPTOR_ARRAY:
2514			updateEntries.push_back(createTemplateBinding(1, 0, 2, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), sizeof(bufferInfos[0])));
2515			break;
2516
2517		default:
2518			DE_FATAL("Impossible");
2519	}
2520
2521	templateCreateInfo.pDescriptorUpdateEntries			= &updateEntries[0];
2522	templateCreateInfo.descriptorUpdateEntryCount		= (deUint32)updateEntries.size();
2523
2524	m_updateTemplate									= vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
2525
2526	if (!withPush)
2527	{
2528		m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, *m_updateTemplate, m_updateRegistry.getRawPointer());
2529	}
2530}
2531
2532tcu::TestStatus BufferComputeInstance::iterate (void)
2533{
2534	logTestPlan();
2535	return testResourceAccess();
2536}
2537
2538void BufferComputeInstance::logTestPlan (void) const
2539{
2540	std::ostringstream msg;
2541
2542	msg << "Accessing resource in a compute program.\n"
2543		<< "Single descriptor set. Descriptor set contains "
2544			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
2545				(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
2546				(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
2547				(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
2548				(const char*)DE_NULL)
2549		<< " source descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType)
2550		<< " and one destination VK_DESCRIPTOR_TYPE_STORAGE_BUFFER to store results to.\n"
2551		<< "Source descriptor buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
2552
2553	if (isDynamicDescriptorType(m_descriptorType))
2554	{
2555		if (m_setDynamicOffset)
2556		{
2557			msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
2558				<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
2559		}
2560		else
2561		{
2562			msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
2563		}
2564	}
2565
2566	msg << "Destination buffer is pre-initialized to -1.\n";
2567
2568	m_context.getTestContext().getLog()
2569		<< tcu::TestLog::Message
2570		<< msg.str()
2571		<< tcu::TestLog::EndMessage;
2572}
2573
2574tcu::TestStatus BufferComputeInstance::testResourceAccess (void)
2575{
2576	enum
2577	{
2578		ADDRESSABLE_SIZE = 256, // allocate a lot more than required
2579	};
2580
2581	const bool										isDynamicCase		= isDynamicDescriptorType(m_descriptorType);
2582	const bool										isUniformBuffer		= isUniformDescriptorType(m_descriptorType);
2583	const deUint32									bindTimeOffsets[]	=
2584	{
2585		(m_dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_A) : (0u),
2586		(m_dynamicOffsetNonZero) ? ((deUint32)DYNAMIC_OFFSET_VALUE_B) : (0u),
2587	};
2588
2589	const tcu::Vec4									colorA1				= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
2590	const tcu::Vec4									colorA2				= tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f);
2591	const tcu::Vec4									colorB1				= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
2592	const tcu::Vec4									colorB2				= tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
2593
2594	const deUint32									dataOffsetA			= ((isDynamicCase) ? (bindTimeOffsets[0]) : 0) + ((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u));
2595	const deUint32									dataOffsetB			= ((isDynamicCase) ? (bindTimeOffsets[1]) : 0) + ((m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u));
2596	const deUint32									viewOffsetA			= (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_A) : (0u);
2597	const deUint32									viewOffsetB			= (m_setViewOffset) ? ((deUint32)STATIC_OFFSET_VALUE_B) : (0u);
2598	const deUint32									bufferSizeA			= dataOffsetA + ADDRESSABLE_SIZE;
2599	const deUint32									bufferSizeB			= dataOffsetB + ADDRESSABLE_SIZE;
2600
2601	de::MovePtr<vk::Allocation>						bufferMemA;
2602	const vk::Unique<vk::VkBuffer>					bufferA				(createColorDataBuffer(dataOffsetA, bufferSizeA, colorA1, colorA2, &bufferMemA));
2603
2604	de::MovePtr<vk::Allocation>						bufferMemB;
2605	const vk::Unique<vk::VkBuffer>					bufferB				((getInterfaceNumResources(m_shaderInterface) == 1u)
2606																			? (vk::Move<vk::VkBuffer>())
2607																			: (createColorDataBuffer(dataOffsetB, bufferSizeB, colorB1, colorB2, &bufferMemB)));
2608
2609	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
2610	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
2611	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout, *bufferA, viewOffsetA, *bufferB, viewOffsetB, m_result.getBuffer()));
2612	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
2613
2614	const vk::VkAccessFlags							inputBit			= (isUniformBuffer) ? (vk::VK_ACCESS_UNIFORM_READ_BIT) : (vk::VK_ACCESS_SHADER_READ_BIT);
2615	const vk::VkBufferMemoryBarrier					bufferBarriers[]	=
2616	{
2617		{
2618			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2619			DE_NULL,
2620			vk::VK_ACCESS_HOST_WRITE_BIT,				// outputMask
2621			inputBit,									// inputMask
2622			VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
2623			VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
2624			*bufferA,									// buffer
2625			(vk::VkDeviceSize)0u,						// offset
2626			(vk::VkDeviceSize)bufferSizeA,				// size
2627		},
2628		{
2629			vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
2630			DE_NULL,
2631			vk::VK_ACCESS_HOST_WRITE_BIT,				// outputMask
2632			inputBit,									// inputMask
2633			VK_QUEUE_FAMILY_IGNORED,					// srcQueueFamilyIndex
2634			VK_QUEUE_FAMILY_IGNORED,					// destQueueFamilyIndex
2635			*bufferB,									// buffer
2636			(vk::VkDeviceSize)0u,						// offset
2637			(vk::VkDeviceSize)bufferSizeB,				// size
2638		}
2639	};
2640
2641	const deUint32									numSrcBuffers		= getInterfaceNumResources(m_shaderInterface);
2642
2643	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
2644	const int										numDescriptorSets	= (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE || m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? 0 : DE_LENGTH_OF_ARRAY(descriptorSets);
2645	const deUint32* const							dynamicOffsets		= (m_setDynamicOffset) ? (bindTimeOffsets) : (DE_NULL);
2646	const deUint32									numDynamicOffsets	= (m_setDynamicOffset) ? (numSrcBuffers) : (0);
2647	const vk::VkBufferMemoryBarrier* const			preBarriers			= bufferBarriers;
2648	const int										numPreBarriers		= numSrcBuffers;
2649	const vk::VkBufferMemoryBarrier* const			postBarriers		= m_result.getResultReadBarrier();
2650	const int										numPostBarriers		= 1;
2651
2652	const ComputeCommand							compute				(m_vki,
2653																		 m_device,
2654																		 pipeline.getPipeline(),
2655																		 pipeline.getPipelineLayout(),
2656																		 tcu::UVec3(4, 1, 1),
2657																		 numDescriptorSets,	descriptorSets,
2658																		 numDynamicOffsets,	dynamicOffsets,
2659																		 numPreBarriers,	preBarriers,
2660																		 numPostBarriers,	postBarriers);
2661
2662	const tcu::Vec4									refQuadrantValue14	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? (colorA2) :
2663																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? (colorB2) :
2664																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS)		? (colorB2) :
2665																		  (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? (colorB2) :
2666																																					(tcu::Vec4(-2.0f));
2667	const tcu::Vec4									refQuadrantValue23	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? (colorA1) :
2668																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? (colorA1) :
2669																		  (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS)		? (colorA1) :
2670																		  (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? (colorA1) :
2671																																					(tcu::Vec4(-2.0f));
2672	const tcu::Vec4									references[4]		=
2673	{
2674		refQuadrantValue14,
2675		refQuadrantValue23,
2676		refQuadrantValue23,
2677		refQuadrantValue14,
2678	};
2679	tcu::Vec4										results[4];
2680
2681	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
2682	{
2683		writeDescriptorSetWithTemplate(DE_NULL, *descriptorSetLayout, *bufferA, viewOffsetA, *bufferB, viewOffsetB, m_result.getBuffer(), true, pipeline.getPipelineLayout());
2684		compute.submitAndWait(m_queueFamilyIndex, m_queue, *m_updateTemplate, (const void*) m_updateRegistry.getRawPointer());
2685	}
2686	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
2687	{
2688		writeDescriptorSet(DE_NULL, *bufferA, viewOffsetA, *bufferB, viewOffsetB, m_result.getBuffer());
2689		compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder);
2690	}
2691	else
2692	{
2693		compute.submitAndWait(m_queueFamilyIndex, m_queue);
2694	}
2695	m_result.readResultContentsTo(&results);
2696
2697	// verify
2698	if (results[0] == references[0] &&
2699		results[1] == references[1] &&
2700		results[2] == references[2] &&
2701		results[3] == references[3])
2702	{
2703		return tcu::TestStatus::pass("Pass");
2704	}
2705	else if (results[0] == tcu::Vec4(-1.0f) &&
2706			 results[1] == tcu::Vec4(-1.0f) &&
2707			 results[2] == tcu::Vec4(-1.0f) &&
2708			 results[3] == tcu::Vec4(-1.0f))
2709	{
2710		m_context.getTestContext().getLog()
2711			<< tcu::TestLog::Message
2712			<< "Result buffer was not written to."
2713			<< tcu::TestLog::EndMessage;
2714		return tcu::TestStatus::fail("Result buffer was not written to");
2715	}
2716	else
2717	{
2718		m_context.getTestContext().getLog()
2719			<< tcu::TestLog::Message
2720			<< "Error expected ["
2721				<< references[0] << ", "
2722				<< references[1] << ", "
2723				<< references[2] << ", "
2724				<< references[3] << "], got ["
2725				<< results[0] << ", "
2726				<< results[1] << ", "
2727				<< results[2] << ", "
2728				<< results[3] << "]"
2729			<< tcu::TestLog::EndMessage;
2730		return tcu::TestStatus::fail("Invalid result values");
2731	}
2732}
2733
2734class QuadrantRendederCase : public vkt::TestCase
2735{
2736public:
2737									QuadrantRendederCase		(tcu::TestContext&		testCtx,
2738																 const char*			name,
2739																 const char*			description,
2740																 glu::GLSLVersion		glslVersion,
2741																 vk::VkShaderStageFlags	exitingStages,
2742																 vk::VkShaderStageFlags	activeStages);
2743private:
2744	virtual std::string				genExtensionDeclarations	(vk::VkShaderStageFlagBits stage) const = 0;
2745	virtual std::string				genResourceDeclarations		(vk::VkShaderStageFlagBits stage, int numUsedBindings) const = 0;
2746	virtual std::string				genResourceAccessSource		(vk::VkShaderStageFlagBits stage) const = 0;
2747	virtual std::string				genNoAccessSource			(void) const = 0;
2748
2749	std::string						genVertexSource				(void) const;
2750	std::string						genTessCtrlSource			(void) const;
2751	std::string						genTessEvalSource			(void) const;
2752	std::string						genGeometrySource			(void) const;
2753	std::string						genFragmentSource			(void) const;
2754	std::string						genComputeSource			(void) const;
2755
2756	void							initPrograms				(vk::SourceCollections& programCollection) const;
2757
2758protected:
2759	const glu::GLSLVersion			m_glslVersion;
2760	const vk::VkShaderStageFlags	m_exitingStages;
2761	const vk::VkShaderStageFlags	m_activeStages;
2762};
2763
2764QuadrantRendederCase::QuadrantRendederCase (tcu::TestContext&		testCtx,
2765											const char*				name,
2766											const char*				description,
2767											glu::GLSLVersion		glslVersion,
2768											vk::VkShaderStageFlags	exitingStages,
2769											vk::VkShaderStageFlags	activeStages)
2770	: vkt::TestCase		(testCtx, name, description)
2771	, m_glslVersion		(glslVersion)
2772	, m_exitingStages	(exitingStages)
2773	, m_activeStages	(activeStages)
2774{
2775	DE_ASSERT((m_exitingStages & m_activeStages) == m_activeStages);
2776}
2777
2778std::string QuadrantRendederCase::genVertexSource (void) const
2779{
2780	const char* const	nextStageName	= ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)	? ("tsc")
2781										: ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)				? ("geo")
2782										: ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)				? ("frag")
2783										: (DE_NULL);
2784	const char* const	fragColorPrec	= ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? "highp" : "mediump";
2785	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
2786	std::ostringstream	buf;
2787
2788	if ((m_activeStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
2789	{
2790		const bool onlyVS = (m_activeStages == vk::VK_SHADER_STAGE_VERTEX_BIT);
2791
2792		// active vertex shader
2793		buf << versionDecl << "\n"
2794			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT)
2795			<< genResourceDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT, 0)
2796			<< "layout(location = 0) out " << fragColorPrec << " vec4 " << nextStageName << "_color;\n"
2797			<< (onlyVS ? "" : "layout(location = 1) flat out highp int " + de::toString(nextStageName) + "_quadrant_id;\n")
2798			<< genPerVertexBlock(vk::VK_SHADER_STAGE_VERTEX_BIT, m_glslVersion)
2799			<< "void main (void)\n"
2800			<< "{\n"
2801			<< "	highp vec4 result_position;\n"
2802			<< "	highp int quadrant_id;\n"
2803			<< s_quadrantGenVertexPosSource
2804			<< "	gl_Position = result_position;\n"
2805			<< (onlyVS ? "" : "\t" + de::toString(nextStageName) + "_quadrant_id = quadrant_id;\n")
2806			<< "\n"
2807			<< "	highp vec4 result_color;\n"
2808			<< genResourceAccessSource(vk::VK_SHADER_STAGE_VERTEX_BIT)
2809			<< "	" << nextStageName << "_color = result_color;\n"
2810			<< "}\n";
2811	}
2812	else
2813	{
2814		// do nothing
2815		buf << versionDecl << "\n"
2816			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT)
2817			<< "layout(location = 1) flat out highp int " << nextStageName << "_quadrant_id;\n"
2818			<< genPerVertexBlock(vk::VK_SHADER_STAGE_VERTEX_BIT, m_glslVersion)
2819			<< "void main (void)\n"
2820			<< "{\n"
2821			<< "	highp vec4 result_position;\n"
2822			<< "	highp int quadrant_id;\n"
2823			<< s_quadrantGenVertexPosSource
2824			<< "	gl_Position = result_position;\n"
2825			<< "	" << nextStageName << "_quadrant_id = quadrant_id;\n"
2826			<< "}\n";
2827	}
2828
2829	return buf.str();
2830}
2831
2832std::string QuadrantRendederCase::genTessCtrlSource (void) const
2833{
2834	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
2835	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
2836	const char* const	tessExtDecl		= extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
2837	std::ostringstream	buf;
2838
2839	if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
2840	{
2841		// contributing not implemented
2842		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
2843
2844		// active tc shader
2845		buf << versionDecl << "\n"
2846			<< tessExtDecl
2847			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
2848			<< "layout(vertices=3) out;\n"
2849			<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 0)
2850			<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
2851			<< "layout(location = 0) out highp vec4 tes_color[];\n"
2852			<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_glslVersion)
2853			<< "void main (void)\n"
2854			<< "{\n"
2855			<< "	highp vec4 result_color;\n"
2856			<< "	highp int quadrant_id = tsc_quadrant_id[gl_InvocationID];\n"
2857			<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
2858			<< "\n"
2859			<< "	tes_color[gl_InvocationID] = result_color;\n"
2860			<< "\n"
2861			<< "	// no dynamic input block indexing\n"
2862			<< "	highp vec4 position;\n"
2863			<< "	if (gl_InvocationID == 0)\n"
2864			<< "		position = gl_in[0].gl_Position;\n"
2865			<< "	else if (gl_InvocationID == 1)\n"
2866			<< "		position = gl_in[1].gl_Position;\n"
2867			<< "	else\n"
2868			<< "		position = gl_in[2].gl_Position;\n"
2869			<< "	gl_out[gl_InvocationID].gl_Position = position;\n"
2870			<< "	gl_TessLevelInner[0] = 2.8;\n"
2871			<< "	gl_TessLevelInner[1] = 2.8;\n"
2872			<< "	gl_TessLevelOuter[0] = 2.8;\n"
2873			<< "	gl_TessLevelOuter[1] = 2.8;\n"
2874			<< "	gl_TessLevelOuter[2] = 2.8;\n"
2875			<< "	gl_TessLevelOuter[3] = 2.8;\n"
2876			<< "}\n";
2877	}
2878	else if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
2879	{
2880		// active te shader, tc passthru
2881		buf << versionDecl << "\n"
2882			<< tessExtDecl
2883			<< "layout(vertices=3) out;\n"
2884			<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
2885			<< "layout(location = 1) flat out highp int tes_quadrant_id[];\n"
2886			<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_glslVersion)
2887			<< "void main (void)\n"
2888			<< "{\n"
2889			<< "	tes_quadrant_id[gl_InvocationID] = tsc_quadrant_id[0];\n"
2890			<< "\n"
2891			<< "	// no dynamic input block indexing\n"
2892			<< "	highp vec4 position;\n"
2893			<< "	if (gl_InvocationID == 0)\n"
2894			<< "		position = gl_in[0].gl_Position;\n"
2895			<< "	else if (gl_InvocationID == 1)\n"
2896			<< "		position = gl_in[1].gl_Position;\n"
2897			<< "	else\n"
2898			<< "		position = gl_in[2].gl_Position;\n"
2899			<< "	gl_out[gl_InvocationID].gl_Position = position;\n"
2900			<< "	gl_TessLevelInner[0] = 2.8;\n"
2901			<< "	gl_TessLevelInner[1] = 2.8;\n"
2902			<< "	gl_TessLevelOuter[0] = 2.8;\n"
2903			<< "	gl_TessLevelOuter[1] = 2.8;\n"
2904			<< "	gl_TessLevelOuter[2] = 2.8;\n"
2905			<< "	gl_TessLevelOuter[3] = 2.8;\n"
2906			<< "}\n";
2907	}
2908	else
2909	{
2910		// passthrough not implemented
2911		DE_FATAL("not implemented");
2912	}
2913
2914	return buf.str();
2915}
2916
2917std::string QuadrantRendederCase::genTessEvalSource (void) const
2918{
2919	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
2920	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
2921	const char* const	tessExtDecl		= extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
2922	std::ostringstream	buf;
2923
2924	if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
2925	{
2926		// contributing not implemented
2927		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
2928
2929		// active te shader
2930		buf << versionDecl << "\n"
2931			<< tessExtDecl
2932			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
2933			<< "layout(triangles) in;\n"
2934			<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 0)
2935			<< "layout(location = 1) flat in highp int tes_quadrant_id[];\n"
2936			<< "layout(location = 0) out mediump vec4 frag_color;\n"
2937			<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_glslVersion)
2938			<< "void main (void)\n"
2939			<< "{\n"
2940			<< "	highp vec4 result_color;\n"
2941			<< "	highp int quadrant_id = tes_quadrant_id[0];\n"
2942			<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
2943			<< "\n"
2944			<< "	frag_color = result_color;\n"
2945			<< "	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
2946			<< "}\n";
2947	}
2948	else if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
2949	{
2950		// contributing not implemented
2951		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
2952
2953		// active tc shader, te is passthru
2954		buf << versionDecl << "\n"
2955			<< tessExtDecl
2956			<< "layout(triangles) in;\n"
2957			<< "layout(location = 0) in highp vec4 tes_color[];\n"
2958			<< "layout(location = 0) out mediump vec4 frag_color;\n"
2959			<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_glslVersion)
2960			<< "void main (void)\n"
2961			<< "{\n"
2962			<< "	frag_color = tes_color[0];\n"
2963			<< "	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
2964			<< "}\n";
2965	}
2966	else
2967	{
2968		// passthrough not implemented
2969		DE_FATAL("not implemented");
2970	}
2971
2972	return buf.str();
2973}
2974
2975std::string QuadrantRendederCase::genGeometrySource (void) const
2976{
2977	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
2978	const bool			extRequired		= glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
2979	const char* const	geomExtDecl		= extRequired ? "#extension GL_EXT_geometry_shader : require\n" : "";
2980	std::ostringstream	buf;
2981
2982	if ((m_activeStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
2983	{
2984		// contributing not implemented
2985		DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_GEOMETRY_BIT);
2986
2987		// active geometry shader
2988		buf << versionDecl << "\n"
2989			<< geomExtDecl
2990			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
2991			<< "layout(triangles) in;\n"
2992			<< "layout(triangle_strip, max_vertices=4) out;\n"
2993			<< genResourceDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT, 0)
2994			<< "layout(location = 1) flat in highp int geo_quadrant_id[];\n"
2995			<< "layout(location = 0) out mediump vec4 frag_color;\n"
2996			<< genPerVertexBlock(vk::VK_SHADER_STAGE_GEOMETRY_BIT, m_glslVersion)
2997			<< "void main (void)\n"
2998			<< "{\n"
2999			<< "	highp int quadrant_id;\n"
3000			<< "	highp vec4 result_color;\n"
3001			<< "\n"
3002			<< "	quadrant_id = geo_quadrant_id[0];\n"
3003			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
3004			<< "	frag_color = result_color;\n"
3005			<< "	gl_Position = gl_in[0].gl_Position;\n"
3006			<< "	EmitVertex();\n"
3007			<< "\n"
3008			<< "	quadrant_id = geo_quadrant_id[1];\n"
3009			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
3010			<< "	frag_color = result_color;\n"
3011			<< "	gl_Position = gl_in[1].gl_Position;\n"
3012			<< "	EmitVertex();\n"
3013			<< "\n"
3014			<< "	quadrant_id = geo_quadrant_id[2];\n"
3015			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
3016			<< "	frag_color = result_color;\n"
3017			<< "	gl_Position = gl_in[0].gl_Position * 0.5 + gl_in[2].gl_Position * 0.5;\n"
3018			<< "	EmitVertex();\n"
3019			<< "\n"
3020			<< "	quadrant_id = geo_quadrant_id[0];\n"
3021			<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
3022			<< "	frag_color = result_color;\n"
3023			<< "	gl_Position = gl_in[2].gl_Position;\n"
3024			<< "	EmitVertex();\n"
3025			<< "}\n";
3026	}
3027	else
3028	{
3029		// passthrough not implemented
3030		DE_FATAL("not implemented");
3031	}
3032
3033	return buf.str();
3034}
3035
3036std::string QuadrantRendederCase::genFragmentSource (void) const
3037{
3038	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
3039	std::ostringstream	buf;
3040
3041	if ((m_activeStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
3042	{
3043		buf << versionDecl << "\n"
3044			<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
3045			<< genResourceDeclarations(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0);
3046
3047		if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
3048		{
3049			// there are other stages, this is just a contributor
3050			buf << "layout(location = 0) in mediump vec4 frag_color;\n";
3051		}
3052
3053		buf << "layout(location = 1) flat in highp int frag_quadrant_id;\n"
3054			<< "layout(location = 0) out mediump vec4 o_color;\n"
3055			<< "void main (void)\n"
3056			<< "{\n"
3057			<< "	highp int quadrant_id = frag_quadrant_id;\n"
3058			<< "	highp vec4 result_color;\n"
3059			<< genResourceAccessSource(vk::VK_SHADER_STAGE_FRAGMENT_BIT);
3060
3061		if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
3062		{
3063			// just contributor
3064			buf	<< "	if (frag_quadrant_id < 2)\n"
3065				<< "		o_color = result_color;\n"
3066				<< "	else\n"
3067				<< "		o_color = frag_color;\n";
3068		}
3069		else
3070			buf << "	o_color = result_color;\n";
3071
3072		buf << "}\n";
3073	}
3074	else if (m_activeStages == 0u)
3075	{
3076		// special case, no active stages
3077		buf << versionDecl << "\n"
3078			<< "layout(location = 1) flat in highp int frag_quadrant_id;\n"
3079			<< "layout(location = 0) out mediump vec4 o_color;\n"
3080			<< "void main (void)\n"
3081			<< "{\n"
3082			<< "	highp int quadrant_id = frag_quadrant_id;\n"
3083			<< "	highp vec4 result_color;\n"
3084			<< genNoAccessSource()
3085			<< "	o_color = result_color;\n"
3086			<< "}\n";
3087	}
3088	else
3089	{
3090		// passthrough
3091		buf <<	versionDecl << "\n"
3092			<<	"layout(location = 0) in mediump vec4 frag_color;\n"
3093				"layout(location = 0) out mediump vec4 o_color;\n"
3094				"void main (void)\n"
3095				"{\n"
3096				"	o_color = frag_color;\n"
3097				"}\n";
3098	}
3099
3100	return buf.str();
3101}
3102
3103std::string QuadrantRendederCase::genComputeSource (void) const
3104{
3105	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
3106	std::ostringstream	buf;
3107
3108	buf	<< versionDecl << "\n"
3109		<< genExtensionDeclarations(vk::VK_SHADER_STAGE_COMPUTE_BIT)
3110		<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
3111		<< genResourceDeclarations(vk::VK_SHADER_STAGE_COMPUTE_BIT, 1)
3112		<< "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
3113		<< "{\n"
3114		<< "	highp vec4 read_colors[4];\n"
3115		<< "} b_out;\n"
3116		<< "void main (void)\n"
3117		<< "{\n"
3118		<< "	highp int quadrant_id = int(gl_WorkGroupID.x);\n"
3119		<< "	highp vec4 result_color;\n"
3120		<< genResourceAccessSource(vk::VK_SHADER_STAGE_COMPUTE_BIT)
3121		<< "	b_out.read_colors[gl_WorkGroupID.x] = result_color;\n"
3122		<< "}\n";
3123
3124	return buf.str();
3125}
3126
3127void QuadrantRendederCase::initPrograms (vk::SourceCollections& programCollection) const
3128{
3129	if ((m_exitingStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
3130		programCollection.glslSources.add("vertex") << glu::VertexSource(genVertexSource());
3131
3132	if ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
3133		programCollection.glslSources.add("tess_ctrl") << glu::TessellationControlSource(genTessCtrlSource());
3134
3135	if ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
3136		programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(genTessEvalSource());
3137
3138	if ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
3139		programCollection.glslSources.add("geometry") << glu::GeometrySource(genGeometrySource());
3140
3141	if ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
3142		programCollection.glslSources.add("fragment") << glu::FragmentSource(genFragmentSource());
3143
3144	if ((m_exitingStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) != 0u)
3145		programCollection.glslSources.add("compute") << glu::ComputeSource(genComputeSource());
3146}
3147
3148class BufferDescriptorCase : public QuadrantRendederCase
3149{
3150public:
3151	enum
3152	{
3153		FLAG_VIEW_OFFSET			= (1u << 1u),
3154		FLAG_DYNAMIC_OFFSET_ZERO	= (1u << 2u),
3155		FLAG_DYNAMIC_OFFSET_NONZERO	= (1u << 3u),
3156	};
3157	// enum continues where resource flags ends
3158	DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
3159
3160									BufferDescriptorCase		(tcu::TestContext&		testCtx,
3161																 DescriptorUpdateMethod	updateMethod,
3162																 const char*			name,
3163																 const char*			description,
3164																 bool					isPrimaryCmdBuf,
3165																 vk::VkDescriptorType	descriptorType,
3166																 vk::VkShaderStageFlags	exitingStages,
3167																 vk::VkShaderStageFlags	activeStages,
3168																 ShaderInputInterface	shaderInterface,
3169																 deUint32				flags);
3170
3171private:
3172	std::string						genExtensionDeclarations	(vk::VkShaderStageFlagBits stage) const;
3173	std::string						genResourceDeclarations		(vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
3174	std::string						genResourceAccessSource		(vk::VkShaderStageFlagBits stage) const;
3175	std::string						genNoAccessSource			(void) const;
3176
3177	vkt::TestInstance*				createInstance				(vkt::Context& context) const;
3178
3179	const DescriptorUpdateMethod	m_updateMethod;
3180	const bool						m_viewOffset;
3181	const bool						m_dynamicOffsetSet;
3182	const bool						m_dynamicOffsetNonZero;
3183	const bool						m_isPrimaryCmdBuf;
3184	const vk::VkDescriptorType		m_descriptorType;
3185	const ShaderInputInterface		m_shaderInterface;
3186};
3187
3188BufferDescriptorCase::BufferDescriptorCase (tcu::TestContext&		testCtx,
3189											DescriptorUpdateMethod	updateMethod,
3190											const char*				name,
3191											const char*				description,
3192											bool					isPrimaryCmdBuf,
3193											vk::VkDescriptorType	descriptorType,
3194											vk::VkShaderStageFlags	exitingStages,
3195											vk::VkShaderStageFlags	activeStages,
3196											ShaderInputInterface	shaderInterface,
3197											deUint32				flags)
3198	: QuadrantRendederCase		(testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages)
3199	, m_updateMethod			(updateMethod)
3200	, m_viewOffset				((flags & FLAG_VIEW_OFFSET) != 0u)
3201	, m_dynamicOffsetSet		((flags & (FLAG_DYNAMIC_OFFSET_ZERO | FLAG_DYNAMIC_OFFSET_NONZERO)) != 0u)
3202	, m_dynamicOffsetNonZero	((flags & FLAG_DYNAMIC_OFFSET_NONZERO) != 0u)
3203	, m_isPrimaryCmdBuf			(isPrimaryCmdBuf)
3204	, m_descriptorType			(descriptorType)
3205	, m_shaderInterface			(shaderInterface)
3206{
3207}
3208
3209std::string BufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
3210{
3211	DE_UNREF(stage);
3212	return "";
3213}
3214
3215std::string BufferDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
3216{
3217	DE_UNREF(stage);
3218
3219	const bool			isUniform		= isUniformDescriptorType(m_descriptorType);
3220	const char* const	storageType		= (isUniform) ? ("uniform") : ("buffer");
3221	std::ostringstream	buf;
3222
3223	switch (m_shaderInterface)
3224	{
3225		case SHADER_INPUT_SINGLE_DESCRIPTOR:
3226			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferName\n"
3227				<< "{\n"
3228				<< "	highp vec4 colorA;\n"
3229				<< "	highp vec4 colorB;\n"
3230				<< "} b_instance;\n";
3231			break;
3232
3233		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
3234			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferNameA\n"
3235				<< "{\n"
3236				<< "	highp vec4 colorA;\n"
3237				<< "	highp vec4 colorB;\n"
3238				<< "} b_instanceA;\n"
3239				<< "layout(set = 0, binding = " << (numUsedBindings+1) << ", std140) " << storageType << " BufferNameB\n"
3240				<< "{\n"
3241				<< "	highp vec4 colorA;\n"
3242				<< "	highp vec4 colorB;\n"
3243				<< "} b_instanceB;\n";
3244			break;
3245
3246		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
3247			buf	<< "layout(set = 0, binding = " << de::toString(0x7FFEu) << ", std140) " << storageType << " BufferNameA\n"
3248				<< "{\n"
3249				<< "	highp vec4 colorA;\n"
3250				<< "	highp vec4 colorB;\n"
3251				<< "} b_instanceA;\n"
3252				<< "layout(set = 0, binding = " << de::toString(0xFFFEu) << ", std140) " << storageType << " BufferNameB\n"
3253				<< "{\n"
3254				<< "	highp vec4 colorA;\n"
3255				<< "	highp vec4 colorB;\n"
3256				<< "} b_instanceB;\n";
3257			break;
3258
3259		case SHADER_INPUT_DESCRIPTOR_ARRAY:
3260			buf	<< "layout(set = 0, binding = " << (numUsedBindings) << ", std140) " << storageType << " BufferName\n"
3261				<< "{\n"
3262				<< "	highp vec4 colorA;\n"
3263				<< "	highp vec4 colorB;\n"
3264				<< "} b_instances[2];\n";
3265			break;
3266
3267		default:
3268			DE_FATAL("Impossible");
3269	}
3270
3271	return buf.str();
3272}
3273
3274std::string BufferDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
3275{
3276	DE_UNREF(stage);
3277
3278	std::ostringstream buf;
3279
3280	switch (m_shaderInterface)
3281	{
3282		case SHADER_INPUT_SINGLE_DESCRIPTOR:
3283			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
3284				<< "		result_color = b_instance.colorA;\n"
3285				<< "	else\n"
3286				<< "		result_color = b_instance.colorB;\n";
3287			break;
3288
3289		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
3290			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
3291				<< "		result_color = b_instanceA.colorA;\n"
3292				<< "	else\n"
3293				<< "		result_color = b_instanceB.colorB;\n";
3294			break;
3295
3296		case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
3297			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
3298				<< "		result_color = b_instanceA.colorA;\n"
3299				<< "	else\n"
3300				<< "		result_color = b_instanceB.colorB;\n";
3301			break;
3302
3303		case SHADER_INPUT_DESCRIPTOR_ARRAY:
3304			buf << "	if (quadrant_id == 1 || quadrant_id == 2)\n"
3305				<< "		result_color = b_instances[0].colorA;\n"
3306				<< "	else\n"
3307				<< "		result_color = b_instances[1].colorB;\n";
3308			break;
3309
3310		default:
3311			DE_FATAL("Impossible");
3312	}
3313
3314	return buf.str();
3315}
3316
3317std::string BufferDescriptorCase::genNoAccessSource (void) const
3318{
3319	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
3320		   "		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
3321		   "	else\n"
3322		   "		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
3323}
3324
3325vkt::TestInstance* BufferDescriptorCase::createInstance (vkt::Context& context) const
3326{
3327	verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages);
3328
3329	if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
3330	{
3331		DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
3332		return new BufferComputeInstance(context, m_updateMethod, m_descriptorType, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
3333	}
3334	else
3335		return new BufferRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
3336}
3337
3338class ImageInstanceImages
3339{
3340public:
3341										ImageInstanceImages		(const vk::DeviceInterface&		vki,
3342																 vk::VkDevice					device,
3343																 deUint32						queueFamilyIndex,
3344																 vk::VkQueue					queue,
3345																 vk::Allocator&					allocator,
3346																 vk::VkDescriptorType			descriptorType,
3347																 vk::VkImageViewType			viewType,
3348																 int							numImages,
3349																 deUint32						baseMipLevel,
3350																 deUint32						baseArraySlice);
3351
3352private:
3353	static vk::Move<vk::VkImage>		createImage				(const vk::DeviceInterface&			vki,
3354																 vk::VkDevice						device,
3355																 vk::Allocator&						allocator,
3356																 vk::VkDescriptorType				descriptorType,
3357																 vk::VkImageViewType				viewType,
3358																 const tcu::TextureLevelPyramid&	sourceImage,
3359																 de::MovePtr<vk::Allocation>*		outAllocation);
3360
3361	static vk::Move<vk::VkImageView>	createImageView			(const vk::DeviceInterface&			vki,
3362																 vk::VkDevice						device,
3363																 vk::VkImageViewType				viewType,
3364																 const tcu::TextureLevelPyramid&	sourceImage,
3365																 vk::VkImage						image,
3366																 deUint32							baseMipLevel,
3367																 deUint32							baseArraySlice);
3368
3369	void								populateSourceImage		(tcu::TextureLevelPyramid*			dst,
3370																 bool								isFirst) const;
3371
3372	void								uploadImage				(const vk::DeviceInterface&			vki,
3373																 vk::VkDevice						device,
3374																 deUint32							queueFamilyIndex,
3375																 vk::VkQueue						queue,
3376																 vk::Allocator&						allocator,
3377																 vk::VkImage						image,
3378																 vk::VkImageLayout					layout,
3379																 const tcu::TextureLevelPyramid&	data);
3380
3381protected:
3382	enum
3383	{
3384		IMAGE_SIZE		= 64,
3385		NUM_MIP_LEVELS	= 2,
3386		ARRAY_SIZE		= 2,
3387	};
3388
3389	const vk::VkImageViewType			m_viewType;
3390	const deUint32						m_baseMipLevel;
3391	const deUint32						m_baseArraySlice;
3392
3393	const tcu::TextureFormat			m_imageFormat;
3394	tcu::TextureLevelPyramid			m_sourceImageA;
3395	tcu::TextureLevelPyramid			m_sourceImageB;
3396
3397	de::MovePtr<vk::Allocation>			m_imageMemoryA;
3398	de::MovePtr<vk::Allocation>			m_imageMemoryB;
3399	vk::Move<vk::VkImage>				m_imageA;
3400	vk::Move<vk::VkImage>				m_imageB;
3401	vk::Move<vk::VkImageView>			m_imageViewA;
3402	vk::Move<vk::VkImageView>			m_imageViewB;
3403};
3404
3405ImageInstanceImages::ImageInstanceImages (const vk::DeviceInterface&	vki,
3406										  vk::VkDevice					device,
3407										  deUint32						queueFamilyIndex,
3408										  vk::VkQueue					queue,
3409										  vk::Allocator&				allocator,
3410										  vk::VkDescriptorType			descriptorType,
3411										  vk::VkImageViewType			viewType,
3412										  int							numImages,
3413										  deUint32						baseMipLevel,
3414										  deUint32						baseArraySlice)
3415	: m_viewType		(viewType)
3416	, m_baseMipLevel	(baseMipLevel)
3417	, m_baseArraySlice	(baseArraySlice)
3418	, m_imageFormat		(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
3419	, m_sourceImageA	(m_imageFormat, NUM_MIP_LEVELS)
3420	, m_sourceImageB	(m_imageFormat, NUM_MIP_LEVELS)
3421	, m_imageMemoryA	(DE_NULL)
3422	, m_imageMemoryB	(DE_NULL)
3423	, m_imageA			(vk::Move<vk::VkImage>())
3424	, m_imageB			(vk::Move<vk::VkImage>())
3425	, m_imageViewA		(vk::Move<vk::VkImageView>())
3426	, m_imageViewB		(vk::Move<vk::VkImageView>())
3427{
3428	const vk::VkImageLayout	layout	= getImageLayoutForDescriptorType(descriptorType);
3429
3430	DE_ASSERT(numImages == 1 || numImages == 2);
3431
3432	populateSourceImage(&m_sourceImageA, true);
3433	m_imageA = createImage(vki, device, allocator, descriptorType, viewType, m_sourceImageA, &m_imageMemoryA);
3434	m_imageViewA = createImageView(vki, device, viewType, m_sourceImageA, *m_imageA, m_baseMipLevel, m_baseArraySlice);
3435	uploadImage(vki, device, queueFamilyIndex, queue, allocator, *m_imageA, layout, m_sourceImageA);
3436
3437	if (numImages == 2)
3438	{
3439		populateSourceImage(&m_sourceImageB, false);
3440		m_imageB = createImage(vki, device, allocator, descriptorType, viewType, m_sourceImageB, &m_imageMemoryB);
3441		m_imageViewB = createImageView(vki, device, viewType, m_sourceImageB, *m_imageB, m_baseMipLevel, m_baseArraySlice);
3442		uploadImage(vki, device, queueFamilyIndex, queue, allocator, *m_imageB, layout, m_sourceImageB);
3443	}
3444}
3445
3446vk::Move<vk::VkImage> ImageInstanceImages::createImage (const vk::DeviceInterface&			vki,
3447														vk::VkDevice						device,
3448														vk::Allocator&						allocator,
3449														vk::VkDescriptorType				descriptorType,
3450														vk::VkImageViewType					viewType,
3451														const tcu::TextureLevelPyramid&		sourceImage,
3452														de::MovePtr<vk::Allocation>*		outAllocation)
3453{
3454	const tcu::ConstPixelBufferAccess	baseLevel	= sourceImage.getLevel(0);
3455	const bool							isCube		= (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
3456	const bool							isStorage	= (descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
3457	const deUint32						readUsage	= (isStorage) ? (vk::VK_IMAGE_USAGE_STORAGE_BIT) : (vk::VK_IMAGE_USAGE_SAMPLED_BIT);
3458	const deUint32						arraySize	= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (baseLevel.getHeight())
3459													: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (baseLevel.getDepth())
3460													: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)														? (1)
3461													: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (baseLevel.getDepth()) // cube: numFaces * numLayers
3462																																					: (0);
3463	const vk::VkExtent3D				extent		=
3464	{
3465		// x
3466		(deUint32)baseLevel.getWidth(),
3467
3468		// y
3469		(viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1u) : (deUint32)baseLevel.getHeight(),
3470
3471		// z
3472		(viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ((deUint32)baseLevel.getDepth()) : (1u),
3473	};
3474	const vk::VkImageCreateInfo			createInfo	=
3475	{
3476		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
3477		DE_NULL,
3478		isCube ? (vk::VkImageCreateFlags)vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (vk::VkImageCreateFlags)0,
3479		viewTypeToImageType(viewType),											// imageType
3480		vk::mapTextureFormat(baseLevel.getFormat()),							// format
3481		extent,																	// extent
3482		(deUint32)sourceImage.getNumLevels(),									// mipLevels
3483		arraySize,																// arraySize
3484		vk::VK_SAMPLE_COUNT_1_BIT,												// samples
3485		vk::VK_IMAGE_TILING_OPTIMAL,											// tiling
3486		readUsage | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT,						// usage
3487		vk::VK_SHARING_MODE_EXCLUSIVE,											// sharingMode
3488		0u,																		// queueFamilyCount
3489		DE_NULL,																// pQueueFamilyIndices
3490		vk::VK_IMAGE_LAYOUT_UNDEFINED,											// initialLayout
3491	};
3492	vk::Move<vk::VkImage>				image		(vk::createImage(vki, device, &createInfo));
3493
3494	*outAllocation = allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any);
3495	return image;
3496}
3497
3498vk::Move<vk::VkImageView> ImageInstanceImages::createImageView (const vk::DeviceInterface&			vki,
3499																vk::VkDevice						device,
3500																vk::VkImageViewType					viewType,
3501																const tcu::TextureLevelPyramid&		sourceImage,
3502																vk::VkImage							image,
3503																deUint32							baseMipLevel,
3504																deUint32							baseArraySlice)
3505{
3506	const tcu::ConstPixelBufferAccess	baseLevel			= sourceImage.getLevel(0);
3507	const deUint32						viewTypeBaseSlice	= (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * baseArraySlice) : (baseArraySlice);
3508	const deUint32						viewArraySize		= (viewType == vk::VK_IMAGE_VIEW_TYPE_1D)			? (1)
3509															: (viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (baseLevel.getHeight() - viewTypeBaseSlice)
3510															: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D)			? (1)
3511															: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (baseLevel.getDepth() - viewTypeBaseSlice)
3512															: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)			? (1)
3513															: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE)			? (6)
3514															: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (baseLevel.getDepth() - viewTypeBaseSlice) // cube: numFaces * numLayers
3515																												: (0);
3516
3517	DE_ASSERT(viewArraySize > 0);
3518
3519	const vk::VkImageSubresourceRange	resourceRange	=
3520	{
3521		vk::VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
3522		baseMipLevel,									// baseMipLevel
3523		sourceImage.getNumLevels() - baseMipLevel,		// mipLevels
3524		viewTypeBaseSlice,								// baseArraySlice
3525		viewArraySize,									// arraySize
3526	};
3527	const vk::VkImageViewCreateInfo		createInfo		=
3528	{
3529		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
3530		DE_NULL,
3531		(vk::VkImageViewCreateFlags)0,
3532		image,											// image
3533		viewType,										// viewType
3534		vk::mapTextureFormat(baseLevel.getFormat()),	// format
3535		{
3536			vk::VK_COMPONENT_SWIZZLE_R,
3537			vk::VK_COMPONENT_SWIZZLE_G,
3538			vk::VK_COMPONENT_SWIZZLE_B,
3539			vk::VK_COMPONENT_SWIZZLE_A
3540		},												// channels
3541		resourceRange,									// subresourceRange
3542	};
3543	return vk::createImageView(vki, device, &createInfo);
3544}
3545
3546void ImageInstanceImages::populateSourceImage (tcu::TextureLevelPyramid* dst, bool isFirst) const
3547{
3548	const int numLevels = dst->getNumLevels();
3549
3550	for (int level = 0; level < numLevels; ++level)
3551	{
3552		const int	width	= IMAGE_SIZE >> level;
3553		const int	height	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (ARRAY_SIZE)
3554																																: (IMAGE_SIZE >> level);
3555		const int	depth	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? (1)
3556							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? (ARRAY_SIZE)
3557							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? (6 * ARRAY_SIZE)
3558							: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? (IMAGE_SIZE >> level)
3559																																: (1);
3560
3561		dst->allocLevel(level, width, height, depth);
3562
3563		{
3564			const tcu::PixelBufferAccess levelAccess = dst->getLevel(level);
3565
3566			for (int z = 0; z < depth; ++z)
3567			for (int y = 0; y < height; ++y)
3568			for (int x = 0; x < width; ++x)
3569			{
3570				const int			gradPos	= x + y + z;
3571				const int			gradMax	= width + height + depth - 3;
3572
3573				const int			red		= 255 * gradPos / gradMax;													//!< gradient from 0 -> max (detects large offset errors)
3574				const int			green	= ((gradPos % 2 == 0) ? (127) : (0)) + ((gradPos % 4 < 3) ? (128) : (0));	//!< 3-level M pattern (detects small offset errors)
3575				const int			blue	= (128 * level / numLevels) + (isFirst ? 127 : 0);							//!< level and image index (detects incorrect lod / image)
3576
3577				DE_ASSERT(de::inRange(red, 0, 255));
3578				DE_ASSERT(de::inRange(green, 0, 255));
3579				DE_ASSERT(de::inRange(blue, 0, 255));
3580
3581				levelAccess.setPixel(tcu::IVec4(red, green, blue, 255), x, y, z);
3582			}
3583		}
3584	}
3585}
3586
3587void ImageInstanceImages::uploadImage (const vk::DeviceInterface&		vki,
3588									   vk::VkDevice						device,
3589									   deUint32							queueFamilyIndex,
3590									   vk::VkQueue						queue,
3591									   vk::Allocator&					allocator,
3592									   vk::VkImage						image,
3593									   vk::VkImageLayout				layout,
3594									   const tcu::TextureLevelPyramid&	data)
3595{
3596	const deUint32						arraySize					= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1) :
3597																	  (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * (deUint32)ARRAY_SIZE) :
3598																	  ((deUint32)ARRAY_SIZE);
3599	const deUint32						dataBufferSize				= getTextureLevelPyramidDataSize(data);
3600	const vk::VkBufferCreateInfo		bufferCreateInfo			=
3601	{
3602		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
3603		DE_NULL,
3604		0u,													// flags
3605		dataBufferSize,										// size
3606		vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,				// usage
3607		vk::VK_SHARING_MODE_EXCLUSIVE,						// sharingMode
3608		0u,													// queueFamilyCount
3609		DE_NULL,											// pQueueFamilyIndices
3610	};
3611	const vk::Unique<vk::VkBuffer>		dataBuffer					(vk::createBuffer(vki, device, &bufferCreateInfo));
3612	const de::MovePtr<vk::Allocation>	dataBufferMemory			= allocateAndBindObjectMemory(vki, device, allocator, *dataBuffer, vk::MemoryRequirement::HostVisible);
3613	const vk::VkBufferMemoryBarrier		preMemoryBarrier			=
3614	{
3615		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
3616		DE_NULL,
3617		vk::VK_ACCESS_HOST_WRITE_BIT,						// outputMask
3618		vk::VK_ACCESS_TRANSFER_READ_BIT,					// inputMask
3619		VK_QUEUE_FAMILY_IGNORED,							// srcQueueFamilyIndex
3620		VK_QUEUE_FAMILY_IGNORED,							// destQueueFamilyIndex
3621		*dataBuffer,										// buffer
3622		0u,													// offset
3623		dataBufferSize,										// size
3624	};
3625	const vk::VkImageSubresourceRange	fullSubrange				=
3626	{
3627		vk::VK_IMAGE_ASPECT_COLOR_BIT,						// aspectMask
3628		0u,													// baseMipLevel
3629		(deUint32)data.getNumLevels(),						// mipLevels
3630		0u,													// baseArraySlice
3631		arraySize,											// arraySize
3632	};
3633	const vk::VkImageMemoryBarrier		preImageBarrier				=
3634	{
3635		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3636		DE_NULL,
3637		0u,													// outputMask
3638		vk::VK_ACCESS_TRANSFER_WRITE_BIT,					// inputMask
3639		vk::VK_IMAGE_LAYOUT_UNDEFINED,						// oldLayout
3640		vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,			// newLayout
3641		VK_QUEUE_FAMILY_IGNORED,							// srcQueueFamilyIndex
3642		VK_QUEUE_FAMILY_IGNORED,							// destQueueFamilyIndex
3643		image,												// image
3644		fullSubrange										// subresourceRange
3645	};
3646	const vk::VkImageMemoryBarrier		postImageBarrier			=
3647	{
3648		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3649		DE_NULL,
3650		vk::VK_ACCESS_TRANSFER_WRITE_BIT,					// outputMask
3651		vk::VK_ACCESS_SHADER_READ_BIT,						// inputMask
3652		vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,			// oldLayout
3653		layout,												// newLayout
3654		VK_QUEUE_FAMILY_IGNORED,							// srcQueueFamilyIndex
3655		VK_QUEUE_FAMILY_IGNORED,							// destQueueFamilyIndex
3656		image,												// image
3657		fullSubrange										// subresourceRange
3658	};
3659	const vk::VkCommandPoolCreateInfo		cmdPoolCreateInfo			=
3660	{
3661		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
3662		DE_NULL,
3663		vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,			// flags
3664		queueFamilyIndex,									// queueFamilyIndex
3665	};
3666	const vk::Unique<vk::VkCommandPool>		cmdPool						(vk::createCommandPool(vki, device, &cmdPoolCreateInfo));
3667	const vk::VkCommandBufferBeginInfo		cmdBufBeginInfo				=
3668	{
3669		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3670		DE_NULL,
3671		vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// flags
3672		(const vk::VkCommandBufferInheritanceInfo*)DE_NULL,
3673	};
3674
3675	const vk::Unique<vk::VkCommandBuffer>	cmd							(vk::allocateCommandBuffer(vki, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3676	const vk::Unique<vk::VkFence>			cmdCompleteFence			(vk::createFence(vki, device));
3677	const deUint64							infiniteTimeout				= ~(deUint64)0u;
3678	std::vector<vk::VkBufferImageCopy>		copySlices;
3679
3680	// copy data to buffer
3681	writeTextureLevelPyramidData(dataBufferMemory->getHostPtr(), dataBufferSize, data, m_viewType , &copySlices);
3682	flushMappedMemoryRange(vki, device, dataBufferMemory->getMemory(), dataBufferMemory->getOffset(), dataBufferSize);
3683
3684	// record command buffer
3685	VK_CHECK(vki.beginCommandBuffer(*cmd, &cmdBufBeginInfo));
3686	vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0,
3687						   0, (const vk::VkMemoryBarrier*)DE_NULL,
3688						   1, &preMemoryBarrier,
3689						   1, &preImageBarrier);
3690	vki.cmdCopyBufferToImage(*cmd, *dataBuffer, image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)copySlices.size(), &copySlices[0]);
3691	vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (vk::VkDependencyFlags)0,
3692						   0, (const vk::VkMemoryBarrier*)DE_NULL,
3693						   0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
3694						   1, &postImageBarrier);
3695	VK_CHECK(vki.endCommandBuffer(*cmd));
3696
3697	// submit and wait for command buffer to complete before killing it
3698	{
3699		const vk::VkSubmitInfo	submitInfo	=
3700		{
3701			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
3702			DE_NULL,
3703			0u,
3704			(const vk::VkSemaphore*)0,
3705			(const vk::VkPipelineStageFlags*)DE_NULL,
3706			1u,
3707			&cmd.get(),
3708			0u,
3709			(const vk::VkSemaphore*)0,
3710		};
3711		VK_CHECK(vki.queueSubmit(queue, 1, &submitInfo, *cmdCompleteFence));
3712	}
3713	VK_CHECK(vki.waitForFences(device, 1, &cmdCompleteFence.get(), 0u, infiniteTimeout)); // \note: timeout is failure
3714}
3715
3716class ImageFetchInstanceImages : private ImageInstanceImages
3717{
3718public:
3719								ImageFetchInstanceImages	(const vk::DeviceInterface&		vki,
3720															 vk::VkDevice					device,
3721															 deUint32						queueFamilyIndex,
3722															 vk::VkQueue					queue,
3723															 vk::Allocator&					allocator,
3724															 vk::VkDescriptorType			descriptorType,
3725															 ShaderInputInterface			shaderInterface,
3726															 vk::VkImageViewType			viewType,
3727															 deUint32						baseMipLevel,
3728															 deUint32						baseArraySlice);
3729
3730	static tcu::IVec3			getFetchPos					(vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int fetchPosNdx);
3731	tcu::Vec4					fetchImageValue				(int fetchPosNdx) const;
3732
3733	inline vk::VkImageView		getImageViewA				(void) const { return *m_imageViewA; }
3734	inline vk::VkImageView		getImageViewB				(void) const { return *m_imageViewB; }
3735
3736private:
3737	enum
3738	{
3739		// some arbitrary sample points for all four quadrants
3740		SAMPLE_POINT_0_X = 6,
3741		SAMPLE_POINT_0_Y = 13,
3742		SAMPLE_POINT_0_Z = 49,
3743
3744		SAMPLE_POINT_1_X = 51,
3745		SAMPLE_POINT_1_Y = 40,
3746		SAMPLE_POINT_1_Z = 44,
3747
3748		SAMPLE_POINT_2_X = 42,
3749		SAMPLE_POINT_2_Y = 26,
3750		SAMPLE_POINT_2_Z = 19,
3751
3752		SAMPLE_POINT_3_X = 25,
3753		SAMPLE_POINT_3_Y = 25,
3754		SAMPLE_POINT_3_Z = 18,
3755	};
3756
3757	const ShaderInputInterface	m_shaderInterface;
3758};
3759
3760ImageFetchInstanceImages::ImageFetchInstanceImages (const vk::DeviceInterface&	vki,
3761													vk::VkDevice				device,
3762													deUint32					queueFamilyIndex,
3763													vk::VkQueue					queue,
3764													vk::Allocator&				allocator,
3765													vk::VkDescriptorType		descriptorType,
3766													ShaderInputInterface		shaderInterface,
3767													vk::VkImageViewType			viewType,
3768													deUint32					baseMipLevel,
3769													deUint32					baseArraySlice)
3770	: ImageInstanceImages	(vki,
3771							 device,
3772							 queueFamilyIndex,
3773							 queue,
3774							 allocator,
3775							 descriptorType,
3776							 viewType,
3777							 getInterfaceNumResources(shaderInterface),	// numImages
3778							 baseMipLevel,
3779							 baseArraySlice)
3780	, m_shaderInterface		(shaderInterface)
3781{
3782}
3783
3784bool isImageViewTypeArray (vk::VkImageViewType type)
3785{
3786	return type == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
3787}
3788
3789tcu::IVec3 ImageFetchInstanceImages::getFetchPos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int fetchPosNdx)
3790{
3791	const tcu::IVec3	fetchPositions[4]	=
3792	{
3793		tcu::IVec3(SAMPLE_POINT_0_X, SAMPLE_POINT_0_Y, SAMPLE_POINT_0_Z),
3794		tcu::IVec3(SAMPLE_POINT_1_X, SAMPLE_POINT_1_Y, SAMPLE_POINT_1_Z),
3795		tcu::IVec3(SAMPLE_POINT_2_X, SAMPLE_POINT_2_Y, SAMPLE_POINT_2_Z),
3796		tcu::IVec3(SAMPLE_POINT_3_X, SAMPLE_POINT_3_Y, SAMPLE_POINT_3_Z),
3797	};
3798	const tcu::IVec3	coord				= de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
3799	const deUint32		imageSize			= (deUint32)IMAGE_SIZE >> baseMipLevel;
3800	const deUint32		arraySize			= isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
3801
3802	switch (viewType)
3803	{
3804		case vk::VK_IMAGE_VIEW_TYPE_1D:
3805		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % arraySize, 0);
3806		case vk::VK_IMAGE_VIEW_TYPE_2D:
3807		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % arraySize);
3808		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
3809		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % (arraySize * 6));
3810		case vk::VK_IMAGE_VIEW_TYPE_3D:			return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % imageSize);
3811		default:
3812			DE_FATAL("Impossible");
3813			return tcu::IVec3();
3814	}
3815}
3816
3817tcu::Vec4 ImageFetchInstanceImages::fetchImageValue (int fetchPosNdx) const
3818{
3819	DE_ASSERT(de::inBounds(fetchPosNdx, 0, 4));
3820
3821	const tcu::TextureLevelPyramid&	fetchSrcA	= m_sourceImageA;
3822	const tcu::TextureLevelPyramid&	fetchSrcB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_sourceImageA) : (m_sourceImageB);
3823	const tcu::TextureLevelPyramid&	fetchSrc	= ((fetchPosNdx % 2) == 0) ? (fetchSrcA) : (fetchSrcB); // sampling order is ABAB
3824	tcu::IVec3						fetchPos	= getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
3825
3826	// add base array layer into the appropriate coordinate, based on the view type
3827	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
3828		fetchPos.z() += 6 * m_baseArraySlice;
3829	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)
3830		fetchPos.y() += m_baseArraySlice;
3831	else
3832		fetchPos.z() += m_baseArraySlice;
3833
3834	return fetchSrc.getLevel(m_baseMipLevel).getPixel(fetchPos.x(), fetchPos.y(), fetchPos.z());
3835}
3836
3837class ImageFetchRenderInstance : public SingleCmdRenderInstance
3838{
3839public:
3840													ImageFetchRenderInstance		(vkt::Context&									context,
3841																					 DescriptorUpdateMethod							updateMethod,
3842																					 bool											isPrimaryCmdBuf,
3843																					 vk::VkDescriptorType							descriptorType,
3844																					 vk::VkShaderStageFlags							stageFlags,
3845																					 ShaderInputInterface							shaderInterface,
3846																					 vk::VkImageViewType							viewType,
3847																					 deUint32										baseMipLevel,
3848																					 deUint32										baseArraySlice);
3849
3850private:
3851	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout		(const vk::DeviceInterface&						vki,
3852																					 vk::VkDevice									device,
3853																					 vk::VkDescriptorType							descriptorType,
3854																					 ShaderInputInterface							shaderInterface,
3855																					 vk::VkShaderStageFlags							stageFlags,
3856																					 DescriptorUpdateMethod							updateMethod);
3857
3858	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout			(const vk::DeviceInterface&						vki,
3859																					 vk::VkDevice									device,
3860																					 vk::VkDescriptorSetLayout						descriptorSetLayout);
3861
3862	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool			(const vk::DeviceInterface&						vki,
3863																					 vk::VkDevice									device,
3864																					 vk::VkDescriptorType							descriptorType,
3865																					 ShaderInputInterface							shaderInterface);
3866
3867	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet				(const vk::DeviceInterface&						vki,
3868																					 DescriptorUpdateMethod							updateMethod,
3869																					 vk::VkDevice									device,
3870																					 vk::VkDescriptorType							descriptorType,
3871																					 ShaderInputInterface							shaderInterface,
3872																					 vk::VkDescriptorSetLayout						layout,
3873																					 vk::VkDescriptorPool							pool,
3874																					 vk::VkImageView								viewA,
3875																					 vk::VkImageView								viewB,
3876																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
3877																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
3878																					 RawUpdateRegistry&								updateRegistry,
3879																					 vk::VkPipelineLayout							pipelineLayout = DE_NULL);
3880
3881	static void										writeDescriptorSet				(const vk::DeviceInterface&						vki,
3882																					 vk::VkDevice									device,
3883																					 vk::VkDescriptorType							descriptorType,
3884																					 ShaderInputInterface							shaderInterface,
3885																					 vk::VkDescriptorSetLayout						layout,
3886																					 vk::VkDescriptorPool							pool,
3887																					 vk::VkImageView								viewA,
3888																					 vk::VkImageView								viewB,
3889																					 vk::VkDescriptorSet							descriptorSet,
3890																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
3891																					 DescriptorUpdateMethod							updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
3892
3893	static void										writeDescriptorSetWithTemplate	(const vk::DeviceInterface&						vki,
3894																					 vk::VkDevice									device,
3895																					 vk::VkDescriptorType							descriptorType,
3896																					 ShaderInputInterface							shaderInterface,
3897																					 vk::VkDescriptorSetLayout						layout,
3898																					 vk::VkDescriptorPool							pool,
3899																					 vk::VkImageView								viewA,
3900																					 vk::VkImageView								viewB,
3901																					 vk::VkDescriptorSet							descriptorSet,
3902																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
3903																					 RawUpdateRegistry&								updateRegistry,
3904																					 bool											withPush = false,
3905																					 vk::VkPipelineLayout							pipelineLayout = 0);
3906
3907	void											logTestPlan						(void) const;
3908	vk::VkPipelineLayout							getPipelineLayout				(void) const;
3909	void											writeDrawCmdBuffer				(vk::VkCommandBuffer cmd) const;
3910	tcu::TestStatus									verifyResultImage				(const tcu::ConstPixelBufferAccess& result) const;
3911
3912	enum
3913	{
3914		RENDER_SIZE = 128,
3915	};
3916
3917	const DescriptorUpdateMethod					m_updateMethod;
3918	const vk::VkDescriptorType						m_descriptorType;
3919	const vk::VkShaderStageFlags					m_stageFlags;
3920	const ShaderInputInterface						m_shaderInterface;
3921	const vk::VkImageViewType						m_viewType;
3922	const deUint32									m_baseMipLevel;
3923	const deUint32									m_baseArraySlice;
3924
3925	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
3926	RawUpdateRegistry								m_updateRegistry;
3927	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
3928	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
3929	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
3930	const ImageFetchInstanceImages					m_images;
3931	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
3932	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
3933};
3934
3935ImageFetchRenderInstance::ImageFetchRenderInstance	(vkt::Context&			context,
3936													 DescriptorUpdateMethod	updateMethod,
3937													 bool					isPrimaryCmdBuf,
3938													 vk::VkDescriptorType	descriptorType,
3939													 vk::VkShaderStageFlags	stageFlags,
3940													 ShaderInputInterface	shaderInterface,
3941													 vk::VkImageViewType	viewType,
3942													 deUint32				baseMipLevel,
3943													 deUint32				baseArraySlice)
3944	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
3945	, m_updateMethod			(updateMethod)
3946	, m_descriptorType			(descriptorType)
3947	, m_stageFlags				(stageFlags)
3948	, m_shaderInterface			(shaderInterface)
3949	, m_viewType				(viewType)
3950	, m_baseMipLevel			(baseMipLevel)
3951	, m_baseArraySlice			(baseArraySlice)
3952	, m_updateTemplate			()
3953	, m_updateRegistry			()
3954	, m_updateBuilder			()
3955	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags, m_updateMethod))
3956	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
3957	, m_images					(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
3958	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
3959	, m_descriptorSet			(createDescriptorSet(m_vki, m_updateMethod, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, m_images.getImageViewA(), m_images.getImageViewB(), m_updateBuilder, m_updateTemplate, m_updateRegistry, *m_pipelineLayout))
3960{
3961}
3962
3963vk::Move<vk::VkDescriptorSetLayout> ImageFetchRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&		vki,
3964																						 vk::VkDevice					device,
3965																						 vk::VkDescriptorType			descriptorType,
3966																						 ShaderInputInterface			shaderInterface,
3967																						 vk::VkShaderStageFlags			stageFlags,
3968																						 DescriptorUpdateMethod			updateMethod)
3969{
3970	vk::DescriptorSetLayoutBuilder			builder;
3971	vk::VkDescriptorSetLayoutCreateFlags	extraFlags			= 0;
3972
3973	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
3974			updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
3975	{
3976		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
3977	}
3978
3979	switch (shaderInterface)
3980	{
3981		case SHADER_INPUT_SINGLE_DESCRIPTOR:
3982			builder.addSingleBinding(descriptorType, stageFlags);
3983			break;
3984
3985		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
3986			builder.addSingleBinding(descriptorType, stageFlags);
3987			builder.addSingleBinding(descriptorType, stageFlags);
3988			break;
3989
3990		case SHADER_INPUT_DESCRIPTOR_ARRAY:
3991			builder.addArrayBinding(descriptorType, 2u, stageFlags);
3992			break;
3993
3994		default:
3995			DE_FATAL("Impossible");
3996	}
3997
3998	return builder.build(vki, device, extraFlags);
3999}
4000
4001vk::Move<vk::VkPipelineLayout> ImageFetchRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
4002																			   vk::VkDevice					device,
4003																			   vk::VkDescriptorSetLayout	descriptorSetLayout)
4004{
4005	const vk::VkPipelineLayoutCreateInfo createInfo =
4006	{
4007		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
4008		DE_NULL,
4009		(vk::VkPipelineLayoutCreateFlags)0,
4010		1,						// descriptorSetCount
4011		&descriptorSetLayout,	// pSetLayouts
4012		0u,						// pushConstantRangeCount
4013		DE_NULL,				// pPushConstantRanges
4014	};
4015	return vk::createPipelineLayout(vki, device, &createInfo);
4016}
4017
4018vk::Move<vk::VkDescriptorPool> ImageFetchRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
4019																			   vk::VkDevice					device,
4020																			   vk::VkDescriptorType			descriptorType,
4021																			   ShaderInputInterface			shaderInterface)
4022{
4023	return vk::DescriptorPoolBuilder()
4024		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
4025		.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
4026}
4027
4028vk::Move<vk::VkDescriptorSet> ImageFetchRenderInstance::createDescriptorSet (const vk::DeviceInterface&						vki,
4029																			 DescriptorUpdateMethod							updateMethod,
4030																			 vk::VkDevice									device,
4031																			 vk::VkDescriptorType							descriptorType,
4032																			 ShaderInputInterface							shaderInterface,
4033																			 vk::VkDescriptorSetLayout						layout,
4034																			 vk::VkDescriptorPool							pool,
4035																			 vk::VkImageView								viewA,
4036																			 vk::VkImageView								viewB,
4037																			 vk::DescriptorSetUpdateBuilder&				updateBuilder,
4038																			 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
4039																			 RawUpdateRegistry&								updateRegistry,
4040																			 vk::VkPipelineLayout							pipelineLayout)
4041{
4042	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
4043	{
4044		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
4045		DE_NULL,
4046		pool,
4047		1u,
4048		&layout
4049	};
4050
4051	vk::Move<vk::VkDescriptorSet>			descriptorSet;
4052	if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
4053	{
4054		descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
4055	}
4056	else
4057	{
4058		descriptorSet = vk::Move<vk::VkDescriptorSet>();
4059	}
4060
4061	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
4062	{
4063		writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplate, updateRegistry);
4064	}
4065	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
4066	{
4067		writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplate, updateRegistry, true, pipelineLayout);
4068	}
4069	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
4070	{
4071		writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, updateMethod);
4072	}
4073	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
4074	{
4075		writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder);
4076	}
4077	return descriptorSet;
4078}
4079
4080void ImageFetchRenderInstance::writeDescriptorSet (const vk::DeviceInterface&		vki,
4081												   vk::VkDevice						device,
4082												   vk::VkDescriptorType				descriptorType,
4083												   ShaderInputInterface				shaderInterface,
4084												   vk::VkDescriptorSetLayout		layout,
4085												   vk::VkDescriptorPool				pool,
4086												   vk::VkImageView					viewA,
4087												   vk::VkImageView					viewB,
4088												   vk::VkDescriptorSet				descriptorSet,
4089												   vk::DescriptorSetUpdateBuilder&	updateBuilder,
4090												   DescriptorUpdateMethod			updateMethod)
4091{
4092	DE_UNREF(layout);
4093	DE_UNREF(pool);
4094	const vk::VkImageLayout									imageLayout			= getImageLayoutForDescriptorType(descriptorType);
4095	const vk::VkDescriptorImageInfo							imageInfos[2]		=
4096	{
4097		makeDescriptorImageInfo(viewA, imageLayout),
4098		makeDescriptorImageInfo(viewB, imageLayout),
4099	};
4100
4101	switch (shaderInterface)
4102	{
4103		case SHADER_INPUT_SINGLE_DESCRIPTOR:
4104			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
4105			break;
4106
4107		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
4108			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
4109			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &imageInfos[1]);
4110			break;
4111
4112		case SHADER_INPUT_DESCRIPTOR_ARRAY:
4113			updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, imageInfos);
4114			break;
4115
4116		default:
4117			DE_FATAL("Impossible");
4118	}
4119
4120	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
4121	{
4122		updateBuilder.update(vki, device);
4123	}
4124}
4125
4126void ImageFetchRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface&					vki,
4127															   vk::VkDevice									device,
4128															   vk::VkDescriptorType							descriptorType,
4129															   ShaderInputInterface							shaderInterface,
4130															   vk::VkDescriptorSetLayout					layout,
4131															   vk::VkDescriptorPool							pool,
4132															   vk::VkImageView								viewA,
4133															   vk::VkImageView								viewB,
4134															   vk::VkDescriptorSet							descriptorSet,
4135															   vk::Move<vk::VkDescriptorUpdateTemplate>&	updateTemplate,
4136															   RawUpdateRegistry&							updateRegistry,
4137															   bool											withPush,
4138															   vk::VkPipelineLayout							pipelineLayout)
4139{
4140	DE_UNREF(pool);
4141	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
4142	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
4143	{
4144		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
4145		DE_NULL,
4146		0,
4147		0,			// updateCount
4148		DE_NULL,	// pUpdates
4149		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
4150		layout,
4151		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
4152		pipelineLayout,
4153		0
4154	};
4155	const vk::VkImageLayout									imageLayout			= getImageLayoutForDescriptorType(descriptorType);
4156	const vk::VkDescriptorImageInfo							imageInfos[2]		=
4157	{
4158		makeDescriptorImageInfo(viewA, imageLayout),
4159		makeDescriptorImageInfo(viewB, imageLayout),
4160	};
4161	updateRegistry.addWriteObject(imageInfos[0]);
4162	updateRegistry.addWriteObject(imageInfos[1]);
4163
4164	switch (shaderInterface)
4165	{
4166		case SHADER_INPUT_SINGLE_DESCRIPTOR:
4167			updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
4168			break;
4169
4170		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
4171			updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
4172			updateEntries.push_back(createTemplateBinding(1, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
4173			break;
4174
4175		case SHADER_INPUT_DESCRIPTOR_ARRAY:
4176			updateEntries.push_back(createTemplateBinding(0, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(imageInfos[0])));
4177			break;
4178
4179		default:
4180			DE_FATAL("Impossible");
4181	}
4182
4183	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
4184	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
4185
4186	updateTemplate									= vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
4187
4188	if (!withPush)
4189	{
4190		vki.updateDescriptorSetWithTemplate(device, descriptorSet, *updateTemplate, updateRegistry.getRawPointer());
4191	}
4192}
4193
4194void ImageFetchRenderInstance::logTestPlan (void) const
4195{
4196	std::ostringstream msg;
4197
4198	msg << "Rendering 2x2 grid.\n"
4199		<< "Single descriptor set. Descriptor set contains "
4200			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
4201			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
4202			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
4203			    (const char*)DE_NULL)
4204		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
4205		<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
4206
4207	if (m_baseMipLevel)
4208		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
4209	if (m_baseArraySlice)
4210		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
4211
4212	if (m_stageFlags == 0u)
4213	{
4214		msg << "Descriptors are not accessed in any shader stage.\n";
4215	}
4216	else
4217	{
4218		msg << "Color in each cell is fetched using the descriptor(s):\n";
4219
4220		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
4221		{
4222			msg << "Test sample " << resultNdx << ": fetching at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
4223
4224			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
4225			{
4226				const int srcResourceNdx = (resultNdx % 2); // ABAB source
4227				msg << " from descriptor " << srcResourceNdx;
4228			}
4229
4230			msg << "\n";
4231		}
4232
4233		msg << "Descriptors are accessed in {"
4234			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)					? (" vertex")			: (""))
4235			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
4236			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
4237			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)				? (" geometry")			: (""))
4238			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)				? (" fragment")			: (""))
4239			<< " } stages.";
4240	}
4241
4242	m_context.getTestContext().getLog()
4243		<< tcu::TestLog::Message
4244		<< msg.str()
4245		<< tcu::TestLog::EndMessage;
4246}
4247
4248vk::VkPipelineLayout ImageFetchRenderInstance::getPipelineLayout (void) const
4249{
4250	return *m_pipelineLayout;
4251}
4252
4253void ImageFetchRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
4254{
4255	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
4256	{
4257		m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
4258	}
4259	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
4260	{
4261		m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, *m_updateTemplate, getPipelineLayout(), 0, (const void*)m_updateRegistry.getRawPointer());
4262	}
4263	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
4264	{
4265		m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0);
4266	}
4267
4268	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
4269}
4270
4271tcu::TestStatus ImageFetchRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
4272{
4273	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
4274	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
4275	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
4276	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_images.fetchImageValue(0));
4277	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_images.fetchImageValue(1));
4278	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_images.fetchImageValue(2));
4279	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_images.fetchImageValue(3));
4280	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
4281
4282	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
4283
4284	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
4285		return tcu::TestStatus::fail("Image verification failed");
4286	else
4287		return tcu::TestStatus::pass("Pass");
4288}
4289
4290class ImageFetchComputeInstance : public vkt::TestInstance
4291{
4292public:
4293													ImageFetchComputeInstance				(vkt::Context&			context,
4294																							 DescriptorUpdateMethod	updateMethod,
4295																							 vk::VkDescriptorType	descriptorType,
4296																							 ShaderInputInterface	shaderInterface,
4297																							 vk::VkImageViewType	viewType,
4298																							 deUint32				baseMipLevel,
4299																							 deUint32				baseArraySlice);
4300
4301private:
4302	vk::Move<vk::VkDescriptorSetLayout>				createDescriptorSetLayout				(void) const;
4303	vk::Move<vk::VkDescriptorPool>					createDescriptorPool					(void) const;
4304	vk::Move<vk::VkDescriptorSet>					createDescriptorSet						(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout);
4305	void											writeDescriptorSet						(vk::VkDescriptorSet descriptorSet);
4306	void											writeDescriptorSetWithTemplate			(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
4307
4308
4309	tcu::TestStatus									iterate									(void);
4310	void											logTestPlan								(void) const;
4311	tcu::TestStatus									testResourceAccess						(void);
4312
4313	const DescriptorUpdateMethod					m_updateMethod;
4314	const vk::VkDescriptorType						m_descriptorType;
4315	const ShaderInputInterface						m_shaderInterface;
4316	const vk::VkImageViewType						m_viewType;
4317	const deUint32									m_baseMipLevel;
4318	const deUint32									m_baseArraySlice;
4319	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
4320
4321	const vk::DeviceInterface&						m_vki;
4322	const vk::VkDevice								m_device;
4323	const vk::VkQueue								m_queue;
4324	const deUint32									m_queueFamilyIndex;
4325	vk::Allocator&									m_allocator;
4326
4327	const ComputeInstanceResultBuffer				m_result;
4328	const ImageFetchInstanceImages					m_images;
4329
4330	RawUpdateRegistry								m_updateRegistry;
4331	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
4332};
4333
4334ImageFetchComputeInstance::ImageFetchComputeInstance (Context&					context,
4335													  DescriptorUpdateMethod	updateMethod,
4336													  vk::VkDescriptorType		descriptorType,
4337													  ShaderInputInterface		shaderInterface,
4338													  vk::VkImageViewType		viewType,
4339													  deUint32					baseMipLevel,
4340													  deUint32					baseArraySlice)
4341	: vkt::TestInstance		(context)
4342	, m_updateMethod		(updateMethod)
4343	, m_descriptorType		(descriptorType)
4344	, m_shaderInterface		(shaderInterface)
4345	, m_viewType			(viewType)
4346	, m_baseMipLevel		(baseMipLevel)
4347	, m_baseArraySlice		(baseArraySlice)
4348	, m_updateTemplate		()
4349	, m_vki					(context.getDeviceInterface())
4350	, m_device				(context.getDevice())
4351	, m_queue				(context.getUniversalQueue())
4352	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
4353	, m_allocator			(context.getDefaultAllocator())
4354	, m_result				(m_vki, m_device, m_allocator)
4355	, m_images				(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
4356	, m_updateRegistry		()
4357	, m_updateBuilder		()
4358{
4359}
4360
4361vk::Move<vk::VkDescriptorSetLayout> ImageFetchComputeInstance::createDescriptorSetLayout (void) const
4362{
4363	vk::DescriptorSetLayoutBuilder			builder;
4364	vk::VkDescriptorSetLayoutCreateFlags	extraFlags = 0;
4365
4366	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
4367			m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
4368	{
4369		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
4370	}
4371
4372	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
4373
4374	switch (m_shaderInterface)
4375	{
4376		case SHADER_INPUT_SINGLE_DESCRIPTOR:
4377			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
4378			break;
4379
4380		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
4381			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
4382			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
4383			break;
4384
4385		case SHADER_INPUT_DESCRIPTOR_ARRAY:
4386			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
4387			break;
4388
4389		default:
4390			DE_FATAL("Impossible");
4391	};
4392
4393	return builder.build(m_vki, m_device, extraFlags);
4394}
4395
4396vk::Move<vk::VkDescriptorPool> ImageFetchComputeInstance::createDescriptorPool (void) const
4397{
4398	return vk::DescriptorPoolBuilder()
4399		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
4400		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
4401		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
4402}
4403
4404vk::Move<vk::VkDescriptorSet> ImageFetchComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout)
4405{
4406	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
4407	{
4408		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
4409		DE_NULL,
4410		pool,
4411		1u,
4412		&layout
4413	};
4414
4415	vk::Move<vk::VkDescriptorSet>			descriptorSet;
4416	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
4417	{
4418		descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
4419	}
4420	else
4421	{
4422		descriptorSet = vk::Move<vk::VkDescriptorSet>();
4423	}
4424
4425	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
4426	{
4427		writeDescriptorSetWithTemplate(*descriptorSet, layout);
4428	}
4429	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
4430	{
4431		writeDescriptorSet(*descriptorSet);
4432	}
4433
4434	return descriptorSet;
4435}
4436
4437void ImageFetchComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet)
4438{
4439	const vk::VkDescriptorBufferInfo	resultInfo		= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
4440	const vk::VkImageLayout				imageLayout		= getImageLayoutForDescriptorType(m_descriptorType);
4441	const vk::VkDescriptorImageInfo		imageInfos[2]	=
4442	{
4443		makeDescriptorImageInfo(m_images.getImageViewA(), imageLayout),
4444		makeDescriptorImageInfo(m_images.getImageViewB(), imageLayout),
4445	};
4446
4447	// result
4448	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
4449
4450	// images
4451	switch (m_shaderInterface)
4452	{
4453		case SHADER_INPUT_SINGLE_DESCRIPTOR:
4454			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &imageInfos[0]);
4455			break;
4456
4457		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
4458			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &imageInfos[0]);
4459			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &imageInfos[1]);
4460			break;
4461
4462		case SHADER_INPUT_DESCRIPTOR_ARRAY:
4463			m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, imageInfos);
4464			break;
4465
4466		default:
4467			DE_FATAL("Impossible");
4468	}
4469
4470	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
4471	{
4472		m_updateBuilder.update(m_vki, m_device);
4473	}
4474}
4475
4476void ImageFetchComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush, vk::VkPipelineLayout pipelineLayout)
4477{
4478	const vk::VkDescriptorBufferInfo						resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
4479	const vk::VkImageLayout									imageLayout			= getImageLayoutForDescriptorType(m_descriptorType);
4480	const vk::VkDescriptorImageInfo							imageInfos[2]		=
4481	{
4482		makeDescriptorImageInfo(m_images.getImageViewA(), imageLayout),
4483		makeDescriptorImageInfo(m_images.getImageViewB(), imageLayout),
4484	};
4485	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
4486	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
4487	{
4488		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
4489		DE_NULL,
4490		0,
4491		0,			// updateCount
4492		DE_NULL,	// pUpdates
4493		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
4494		layout,
4495		vk::VK_PIPELINE_BIND_POINT_COMPUTE,
4496		pipelineLayout,
4497		0
4498	};
4499
4500	m_updateRegistry.addWriteObject(resultInfo);
4501	m_updateRegistry.addWriteObject(imageInfos[0]);
4502	m_updateRegistry.addWriteObject(imageInfos[1]);
4503
4504	// result
4505	updateEntries.push_back(createTemplateBinding(0u, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_updateRegistry.getWriteObjectOffset(0), 0));
4506
4507	// images
4508	switch (m_shaderInterface)
4509	{
4510		case SHADER_INPUT_SINGLE_DESCRIPTOR:
4511			updateEntries.push_back(createTemplateBinding(1u, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
4512			break;
4513
4514		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
4515			updateEntries.push_back(createTemplateBinding(1u, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
4516			updateEntries.push_back(createTemplateBinding(2u, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(2), 0));
4517			break;
4518
4519		case SHADER_INPUT_DESCRIPTOR_ARRAY:
4520			updateEntries.push_back(createTemplateBinding(1u, 0, 2, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), sizeof(imageInfos[0])));
4521			break;
4522
4523		default:
4524			DE_FATAL("Impossible");
4525	}
4526
4527	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
4528	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
4529
4530	m_updateTemplate								= vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
4531
4532	if (!withPush)
4533	{
4534		m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, *m_updateTemplate, m_updateRegistry.getRawPointer());
4535	}
4536}
4537
4538tcu::TestStatus ImageFetchComputeInstance::iterate (void)
4539{
4540	logTestPlan();
4541	return testResourceAccess();
4542}
4543
4544void ImageFetchComputeInstance::logTestPlan (void) const
4545{
4546	std::ostringstream msg;
4547
4548	msg << "Fetching 4 values from image in compute shader.\n"
4549		<< "Single descriptor set. Descriptor set contains "
4550			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
4551			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
4552			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
4553			    (const char*)DE_NULL)
4554		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
4555		<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
4556
4557	if (m_baseMipLevel)
4558		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
4559	if (m_baseArraySlice)
4560		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
4561
4562	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
4563	{
4564		msg << "Test sample " << resultNdx << ": fetch at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
4565
4566		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
4567		{
4568			const int srcResourceNdx = (resultNdx % 2); // ABAB source
4569			msg << " from descriptor " << srcResourceNdx;
4570		}
4571
4572		msg << "\n";
4573	}
4574
4575	m_context.getTestContext().getLog()
4576		<< tcu::TestLog::Message
4577		<< msg.str()
4578		<< tcu::TestLog::EndMessage;
4579}
4580
4581tcu::TestStatus ImageFetchComputeInstance::testResourceAccess (void)
4582{
4583	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
4584	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
4585	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
4586	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
4587
4588	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
4589	const int										numDescriptorSets	= (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE || m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? 0 : DE_LENGTH_OF_ARRAY(descriptorSets);
4590	const deUint32* const							dynamicOffsets		= DE_NULL;
4591	const int										numDynamicOffsets	= 0;
4592	const vk::VkBufferMemoryBarrier* const			preBarriers			= DE_NULL;
4593	const int										numPreBarriers		= 0;
4594	const vk::VkBufferMemoryBarrier* const			postBarriers		= m_result.getResultReadBarrier();
4595	const int										numPostBarriers		= 1;
4596
4597	const ComputeCommand							compute				(m_vki,
4598																		 m_device,
4599																		 pipeline.getPipeline(),
4600																		 pipeline.getPipelineLayout(),
4601																		 tcu::UVec3(4, 1, 1),
4602																		 numDescriptorSets,	descriptorSets,
4603																		 numDynamicOffsets,	dynamicOffsets,
4604																		 numPreBarriers,	preBarriers,
4605																		 numPostBarriers,	postBarriers);
4606
4607	tcu::Vec4										results[4];
4608	bool											anyResultSet		= false;
4609	bool											allResultsOk		= true;
4610
4611	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
4612	{
4613		writeDescriptorSetWithTemplate(DE_NULL, *descriptorSetLayout, true, pipeline.getPipelineLayout());
4614		compute.submitAndWait(m_queueFamilyIndex, m_queue, *m_updateTemplate, (const void*) m_updateRegistry.getRawPointer());
4615	}
4616	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
4617	{
4618		writeDescriptorSet(DE_NULL);
4619		compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder);
4620	}
4621	else
4622	{
4623		compute.submitAndWait(m_queueFamilyIndex, m_queue);
4624	}
4625	m_result.readResultContentsTo(&results);
4626
4627	// verify
4628	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
4629	{
4630		const tcu::Vec4	result				= results[resultNdx];
4631		const tcu::Vec4	reference			= m_images.fetchImageValue(resultNdx);
4632		const tcu::Vec4	conversionThreshold	= tcu::Vec4(1.0f / 255.0f);
4633
4634		if (result != tcu::Vec4(-1.0f))
4635			anyResultSet = true;
4636
4637		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
4638		{
4639			allResultsOk = false;
4640
4641			m_context.getTestContext().getLog()
4642				<< tcu::TestLog::Message
4643				<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
4644				<< tcu::TestLog::EndMessage;
4645		}
4646	}
4647
4648	// read back and verify
4649	if (allResultsOk)
4650		return tcu::TestStatus::pass("Pass");
4651	else if (anyResultSet)
4652		return tcu::TestStatus::fail("Invalid result values");
4653	else
4654	{
4655		m_context.getTestContext().getLog()
4656			<< tcu::TestLog::Message
4657			<< "Result buffer was not written to."
4658			<< tcu::TestLog::EndMessage;
4659		return tcu::TestStatus::fail("Result buffer was not written to");
4660	}
4661}
4662
4663class ImageSampleInstanceImages : private ImageInstanceImages
4664{
4665public:
4666										ImageSampleInstanceImages	(const vk::DeviceInterface&		vki,
4667																	 vk::VkDevice					device,
4668																	 deUint32						queueFamilyIndex,
4669																	 vk::VkQueue					queue,
4670																	 vk::Allocator&					allocator,
4671																	 vk::VkDescriptorType			descriptorType,
4672																	 ShaderInputInterface			shaderInterface,
4673																	 vk::VkImageViewType			viewType,
4674																	 deUint32						baseMipLevel,
4675																	 deUint32						baseArraySlice,
4676																	 bool							immutable);
4677
4678	static tcu::Vec4					getSamplePos				(vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx);
4679	tcu::Vec4							fetchSampleValue			(int samplePosNdx) const;
4680
4681	inline vk::VkImageView				getImageViewA				(void) const { return *m_imageViewA;	}
4682	inline vk::VkImageView				getImageViewB				(void) const { return *m_imageViewB;	}
4683	inline vk::VkSampler				getSamplerA					(void) const { return *m_samplerA;		}
4684	inline vk::VkSampler				getSamplerB					(void) const { return *m_samplerB;		}
4685	inline bool							isImmutable					(void) const { return m_isImmutable;	}
4686
4687private:
4688	static int							getNumImages				(vk::VkDescriptorType descriptorType, ShaderInputInterface shaderInterface);
4689	static tcu::Sampler					createRefSampler			(bool isFirst);
4690	static vk::Move<vk::VkSampler>		createSampler				(const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format);
4691
4692	static tcu::Texture1DArrayView		getRef1DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
4693	static tcu::Texture2DArrayView		getRef2DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
4694	static tcu::Texture3DView			getRef3DView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
4695	static tcu::TextureCubeArrayView	getRefCubeView				(const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
4696
4697	const vk::VkDescriptorType			m_descriptorType;
4698	const ShaderInputInterface			m_shaderInterface;
4699	const bool							m_isImmutable;
4700
4701	const tcu::Sampler					m_refSamplerA;
4702	const tcu::Sampler					m_refSamplerB;
4703	const vk::Unique<vk::VkSampler>		m_samplerA;
4704	const vk::Unique<vk::VkSampler>		m_samplerB;
4705};
4706
4707ImageSampleInstanceImages::ImageSampleInstanceImages (const vk::DeviceInterface&	vki,
4708													  vk::VkDevice					device,
4709													  deUint32						queueFamilyIndex,
4710													  vk::VkQueue					queue,
4711													  vk::Allocator&				allocator,
4712													  vk::VkDescriptorType			descriptorType,
4713													  ShaderInputInterface			shaderInterface,
4714													  vk::VkImageViewType			viewType,
4715													  deUint32						baseMipLevel,
4716													  deUint32						baseArraySlice,
4717													  bool							immutable)
4718	: ImageInstanceImages	(vki,
4719							 device,
4720							 queueFamilyIndex,
4721							 queue,
4722							 allocator,
4723							 descriptorType,
4724							 viewType,
4725							 getNumImages(descriptorType, shaderInterface),
4726							 baseMipLevel,
4727							 baseArraySlice)
4728	, m_descriptorType		(descriptorType)
4729	, m_shaderInterface		(shaderInterface)
4730	, m_isImmutable			(immutable)
4731	, m_refSamplerA			(createRefSampler(true))
4732	, m_refSamplerB			(createRefSampler(false))
4733	, m_samplerA			(createSampler(vki, device, m_refSamplerA, m_imageFormat))
4734	, m_samplerB			((getInterfaceNumResources(m_shaderInterface) == 1u)
4735								? vk::Move<vk::VkSampler>()
4736								: createSampler(vki, device, m_refSamplerB, m_imageFormat))
4737{
4738}
4739
4740tcu::Vec4 ImageSampleInstanceImages::getSamplePos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx)
4741{
4742	DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
4743
4744	const deUint32	imageSize	= (deUint32)IMAGE_SIZE >> baseMipLevel;
4745	const deUint32	arraySize	= isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
4746
4747	// choose arbitrary values that are not ambiguous with NEAREST filtering
4748
4749	switch (viewType)
4750	{
4751		case vk::VK_IMAGE_VIEW_TYPE_1D:
4752		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:
4753		case vk::VK_IMAGE_VIEW_TYPE_2D:
4754		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:
4755		case vk::VK_IMAGE_VIEW_TYPE_3D:
4756		{
4757			const tcu::Vec3	coords[4]	=
4758			{
4759				tcu::Vec3(0.75f,
4760						  0.5f,
4761						  (float)(12u % imageSize) + 0.25f),
4762
4763				tcu::Vec3((float)(23u % imageSize) + 0.25f,
4764						  (float)(73u % imageSize) + 0.5f,
4765						  (float)(16u % imageSize) + 0.5f + (float)imageSize),
4766
4767				tcu::Vec3(-(float)(43u % imageSize) + 0.25f,
4768						  (float)(84u % imageSize) + 0.5f + (float)imageSize,
4769						  (float)(117u % imageSize) + 0.75f),
4770
4771				tcu::Vec3((float)imageSize + 0.5f,
4772						  (float)(75u % imageSize) + 0.25f,
4773						  (float)(83u % imageSize) + 0.25f + (float)imageSize),
4774			};
4775			const deUint32	slices[4]	=
4776			{
4777				0u % arraySize,
4778				4u % arraySize,
4779				9u % arraySize,
4780				2u % arraySize,
4781			};
4782
4783			if (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)
4784				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
4785								 (float)slices[samplePosNdx],
4786								 0.0f,
4787								 0.0f);
4788			else if (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)
4789				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
4790								 coords[samplePosNdx].y() / (float)imageSize,
4791								 (float)slices[samplePosNdx],
4792								 0.0f);
4793			else if (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)
4794				return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
4795								 coords[samplePosNdx].y() / (float)imageSize,
4796								 coords[samplePosNdx].z() / (float)imageSize,
4797								 0.0f);
4798			else
4799			{
4800				DE_FATAL("Impossible");
4801				return tcu::Vec4();
4802			}
4803		}
4804
4805		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
4806		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
4807		{
4808			// \note these values are in [0, texSize]*3 space for convenience
4809			const tcu::Vec3	coords[4]	=
4810			{
4811				tcu::Vec3(0.75f,
4812						  0.5f,
4813						  (float)imageSize),
4814
4815				tcu::Vec3((float)(13u % imageSize) + 0.25f,
4816						  0.0f,
4817						  (float)(16u % imageSize) + 0.5f),
4818
4819				tcu::Vec3(0.0f,
4820						  (float)(84u % imageSize) + 0.5f,
4821						  (float)(10u % imageSize) + 0.75f),
4822
4823				tcu::Vec3((float)imageSize,
4824						  (float)(75u % imageSize) + 0.25f,
4825						  (float)(83u % imageSize) + 0.75f),
4826			};
4827			const deUint32	slices[4]	=
4828			{
4829				1u % arraySize,
4830				2u % arraySize,
4831				9u % arraySize,
4832				5u % arraySize,
4833			};
4834
4835			DE_ASSERT(de::inRange(coords[samplePosNdx].x(), 0.0f, (float)imageSize));
4836			DE_ASSERT(de::inRange(coords[samplePosNdx].y(), 0.0f, (float)imageSize));
4837			DE_ASSERT(de::inRange(coords[samplePosNdx].z(), 0.0f, (float)imageSize));
4838
4839			// map to [-1, 1]*3 space
4840			return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize * 2.0f - 1.0f,
4841							 coords[samplePosNdx].y() / (float)imageSize * 2.0f - 1.0f,
4842							 coords[samplePosNdx].z() / (float)imageSize * 2.0f - 1.0f,
4843							 (float)slices[samplePosNdx]);
4844		}
4845
4846		default:
4847			DE_FATAL("Impossible");
4848			return tcu::Vec4();
4849	}
4850}
4851
4852tcu::Vec4 ImageSampleInstanceImages::fetchSampleValue (int samplePosNdx) const
4853{
4854	DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
4855
4856	// texture order is ABAB
4857	const bool									isSamplerCase	= (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER);
4858	const tcu::TextureLevelPyramid&				sampleSrcA		= m_sourceImageA;
4859	const tcu::TextureLevelPyramid&				sampleSrcB		= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_sourceImageA) : (m_sourceImageB);
4860	const tcu::TextureLevelPyramid&				sampleSrc		= (isSamplerCase) ? (sampleSrcA) : ((samplePosNdx % 2) == 0) ? (sampleSrcA) : (sampleSrcB);
4861
4862	// sampler order is ABAB
4863	const tcu::Sampler&							samplerA		= m_refSamplerA;
4864	const tcu::Sampler&							samplerB		= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (m_refSamplerA) : (m_refSamplerB);
4865	const tcu::Sampler&							sampler			= ((samplePosNdx % 2) == 0) ? (samplerA) : (samplerB);
4866
4867	const tcu::Vec4								samplePos		= getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
4868	const float									lod				= 0.0f;
4869	std::vector<tcu::ConstPixelBufferAccess>	levelStorage;
4870
4871	switch (m_viewType)
4872	{
4873		case vk::VK_IMAGE_VIEW_TYPE_1D:
4874		case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:	return getRef1DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), lod);
4875		case vk::VK_IMAGE_VIEW_TYPE_2D:
4876		case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:	return getRef2DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
4877		case vk::VK_IMAGE_VIEW_TYPE_3D:			return getRef3DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
4878		case vk::VK_IMAGE_VIEW_TYPE_CUBE:
4879		case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:	return getRefCubeView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), samplePos.w(), lod);
4880
4881		default:
4882		{
4883			DE_FATAL("Impossible");
4884			return tcu::Vec4();
4885		}
4886	}
4887}
4888
4889int ImageSampleInstanceImages::getNumImages (vk::VkDescriptorType descriptorType, ShaderInputInterface shaderInterface)
4890{
4891	// If we are testing separate samplers, just one image is enough
4892	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
4893		return 1;
4894	else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
4895	{
4896		// combined: numImages == numSamplers
4897		return getInterfaceNumResources(shaderInterface);
4898	}
4899	else
4900	{
4901		DE_FATAL("Impossible");
4902		return 0;
4903	}
4904}
4905
4906tcu::Sampler ImageSampleInstanceImages::createRefSampler (bool isFirst)
4907{
4908	if (isFirst)
4909	{
4910		// linear, wrapping
4911		return tcu::Sampler(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
4912	}
4913	else
4914	{
4915		// nearest, clamping
4916		return tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
4917	}
4918}
4919
4920vk::Move<vk::VkSampler> ImageSampleInstanceImages::createSampler (const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format)
4921{
4922	const vk::VkSamplerCreateInfo	createInfo		= vk::mapSampler(sampler, format);
4923
4924	return vk::createSampler(vki, device, &createInfo);
4925}
4926
4927tcu::Texture1DArrayView ImageSampleInstanceImages::getRef1DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
4928{
4929	DE_ASSERT(levelStorage->empty());
4930
4931	const deUint32 numSlices = (deUint32)source.getLevel(0).getHeight();
4932	const deUint32 numLevels = (deUint32)source.getNumLevels();
4933
4934	// cut pyramid from baseMipLevel
4935	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
4936	{
4937		// cut levels from baseArraySlice
4938		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
4939		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, baseArraySlice, wholeLevel.getWidth(), numSlices - baseArraySlice);
4940		levelStorage->push_back(cutLevel);
4941	}
4942
4943	return tcu::Texture1DArrayView((int)levelStorage->size(), &levelStorage->front());
4944}
4945
4946tcu::Texture2DArrayView ImageSampleInstanceImages::getRef2DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
4947{
4948	DE_ASSERT(levelStorage->empty());
4949
4950	const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth();
4951	const deUint32 numLevels = (deUint32)source.getNumLevels();
4952
4953	// cut pyramid from baseMipLevel
4954	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
4955	{
4956		// cut levels from baseArraySlice
4957		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
4958		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice, wholeLevel.getWidth(), wholeLevel.getHeight(), numSlices - baseArraySlice);
4959		levelStorage->push_back(cutLevel);
4960	}
4961
4962	return tcu::Texture2DArrayView((int)levelStorage->size(), &levelStorage->front());
4963}
4964
4965tcu::Texture3DView ImageSampleInstanceImages::getRef3DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
4966{
4967	DE_ASSERT(levelStorage->empty());
4968	DE_ASSERT(baseArraySlice == 0);
4969	DE_UNREF(baseArraySlice);
4970
4971	const deUint32 numLevels = (deUint32)source.getNumLevels();
4972
4973	// cut pyramid from baseMipLevel
4974	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
4975		levelStorage->push_back(source.getLevel(level));
4976
4977	return tcu::Texture3DView((int)levelStorage->size(), &levelStorage->front());
4978}
4979
4980tcu::TextureCubeArrayView ImageSampleInstanceImages::getRefCubeView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
4981{
4982	DE_ASSERT(levelStorage->empty());
4983
4984	const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth() / 6;
4985	const deUint32 numLevels = (deUint32)source.getNumLevels();
4986
4987	// cut pyramid from baseMipLevel
4988	for (deUint32 level = baseMipLevel; level < numLevels; ++level)
4989	{
4990		// cut levels from baseArraySlice
4991		const tcu::ConstPixelBufferAccess wholeLevel	= source.getLevel(level);
4992		const tcu::ConstPixelBufferAccess cutLevel		= tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice * 6, wholeLevel.getWidth(), wholeLevel.getHeight(), (numSlices - baseArraySlice) * 6);
4993		levelStorage->push_back(cutLevel);
4994	}
4995
4996	return tcu::TextureCubeArrayView((int)levelStorage->size(), &levelStorage->front());
4997}
4998
4999class ImageSampleRenderInstance : public SingleCmdRenderInstance
5000{
5001public:
5002													ImageSampleRenderInstance					(vkt::Context&			context,
5003																								 DescriptorUpdateMethod updateMethod,
5004																								 bool					isPrimaryCmdBuf,
5005																								 vk::VkDescriptorType	descriptorType,
5006																								 vk::VkShaderStageFlags	stageFlags,
5007																								 ShaderInputInterface	shaderInterface,
5008																								 vk::VkImageViewType	viewType,
5009																								 deUint32				baseMipLevel,
5010																								 deUint32				baseArraySlice,
5011																								 bool					isImmutable);
5012
5013private:
5014	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout					(const vk::DeviceInterface&			vki,
5015																								 vk::VkDevice						device,
5016																								 vk::VkDescriptorType				descriptorType,
5017																								 ShaderInputInterface				shaderInterface,
5018																								 vk::VkShaderStageFlags				stageFlags,
5019																								 const ImageSampleInstanceImages&	images,
5020																								 DescriptorUpdateMethod				updateMethod);
5021
5022	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout						(const vk::DeviceInterface&	vki,
5023																								 vk::VkDevice				device,
5024																								 vk::VkDescriptorSetLayout	descriptorSetLayout);
5025
5026	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool						(const vk::DeviceInterface&	vki,
5027																								 vk::VkDevice				device,
5028																								 vk::VkDescriptorType		descriptorType,
5029																								 ShaderInputInterface		shaderInterface);
5030
5031	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet							(const vk::DeviceInterface&						vki,
5032																								 DescriptorUpdateMethod							updateMethod,
5033																								 vk::VkDevice									device,
5034																								 vk::VkDescriptorType							descriptorType,
5035																								 ShaderInputInterface							shaderInterface,
5036																								 vk::VkDescriptorSetLayout						layout,
5037																								 vk::VkDescriptorPool							pool,
5038																								 bool											isImmutable,
5039																								 const ImageSampleInstanceImages&				images,
5040																								 vk::DescriptorSetUpdateBuilder&				updateBuilder,
5041																								 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
5042																								 RawUpdateRegistry&								updateRegistry,
5043																								 vk::VkPipelineLayout							pipelineLayout = DE_NULL);
5044
5045	static void										writeSamplerDescriptorSet					(const vk::DeviceInterface&						vki,
5046																								 vk::VkDevice									device,
5047																								 ShaderInputInterface							shaderInterface,
5048																								 bool											isImmutable,
5049																								 const ImageSampleInstanceImages&				images,
5050																								 vk::VkDescriptorSet							descriptorSet,
5051																								 vk::DescriptorSetUpdateBuilder&				updateBuilder,
5052																								 DescriptorUpdateMethod							updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
5053
5054	static void										writeImageSamplerDescriptorSet				(const vk::DeviceInterface&						vki,
5055																								 vk::VkDevice									device,
5056																								 ShaderInputInterface							shaderInterface,
5057																								 bool											isImmutable,
5058																								 const ImageSampleInstanceImages&				images,
5059																								 vk::VkDescriptorSet							descriptorSet,
5060																								 vk::DescriptorSetUpdateBuilder&				updateBuilder,
5061																								 DescriptorUpdateMethod							updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
5062
5063	static void										writeSamplerDescriptorSetWithTemplate		(const vk::DeviceInterface&						vki,
5064																								 vk::VkDevice									device,
5065																								 ShaderInputInterface							shaderInterface,
5066																								 bool											isImmutable,
5067																								 const ImageSampleInstanceImages&				images,
5068																								 vk::VkDescriptorSet							descriptorSet,
5069																								 vk::VkDescriptorSetLayout						layout,
5070																								 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
5071																								 RawUpdateRegistry&								updateRegistry,
5072																								 bool											withPush = false,
5073																								 vk::VkPipelineLayout							pipelineLayout = 0);
5074
5075	static void										writeImageSamplerDescriptorSetWithTemplate	(const vk::DeviceInterface&						vki,
5076																								 vk::VkDevice									device,
5077																								 ShaderInputInterface							shaderInterface,
5078																								 bool											isImmutable,
5079																								 const ImageSampleInstanceImages&				images,
5080																								 vk::VkDescriptorSet							descriptorSet,
5081																								 vk::VkDescriptorSetLayout						layout,
5082																								 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
5083																								 RawUpdateRegistry&								updateRegistry,
5084																								 bool											withPush = false,
5085																								 vk::VkPipelineLayout							pipelineLayout = 0);
5086
5087	void											logTestPlan									(void) const;
5088	vk::VkPipelineLayout							getPipelineLayout							(void) const;
5089	void											writeDrawCmdBuffer							(vk::VkCommandBuffer cmd) const;
5090	tcu::TestStatus									verifyResultImage							(const tcu::ConstPixelBufferAccess& result) const;
5091
5092	enum
5093	{
5094		RENDER_SIZE = 128,
5095	};
5096
5097	const DescriptorUpdateMethod					m_updateMethod;
5098	const vk::VkDescriptorType						m_descriptorType;
5099	const vk::VkShaderStageFlags					m_stageFlags;
5100	const ShaderInputInterface						m_shaderInterface;
5101	const vk::VkImageViewType						m_viewType;
5102	const deUint32									m_baseMipLevel;
5103	const deUint32									m_baseArraySlice;
5104
5105	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
5106	RawUpdateRegistry								m_updateRegistry;
5107	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
5108	const ImageSampleInstanceImages					m_images;
5109	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
5110	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
5111	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
5112	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
5113};
5114
5115ImageSampleRenderInstance::ImageSampleRenderInstance (vkt::Context&				context,
5116													  DescriptorUpdateMethod	updateMethod,
5117													  bool						isPrimaryCmdBuf,
5118													  vk::VkDescriptorType		descriptorType,
5119													  vk::VkShaderStageFlags	stageFlags,
5120													  ShaderInputInterface		shaderInterface,
5121													  vk::VkImageViewType		viewType,
5122													  deUint32					baseMipLevel,
5123													  deUint32					baseArraySlice,
5124													  bool						isImmutable)
5125	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
5126	, m_updateMethod			(updateMethod)
5127	, m_descriptorType			(descriptorType)
5128	, m_stageFlags				(stageFlags)
5129	, m_shaderInterface			(shaderInterface)
5130	, m_viewType				(viewType)
5131	, m_baseMipLevel			(baseMipLevel)
5132	, m_baseArraySlice			(baseArraySlice)
5133	, m_updateTemplate			()
5134	, m_updateRegistry			()
5135	, m_updateBuilder			()
5136	, m_images					(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutable)
5137	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags, m_images, m_updateMethod))
5138	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
5139	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
5140	, m_descriptorSet			(createDescriptorSet(m_vki, m_updateMethod, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, isImmutable, m_images, m_updateBuilder, m_updateTemplate, m_updateRegistry, *m_pipelineLayout))
5141{
5142}
5143
5144vk::Move<vk::VkDescriptorSetLayout> ImageSampleRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&		vki,
5145																						  vk::VkDevice						device,
5146																						  vk::VkDescriptorType				descriptorType,
5147																						  ShaderInputInterface				shaderInterface,
5148																						  vk::VkShaderStageFlags			stageFlags,
5149																						  const ImageSampleInstanceImages&	images,
5150																						  DescriptorUpdateMethod			updateMethod)
5151{
5152	const vk::VkSampler						samplers[2] =
5153	{
5154		images.getSamplerA(),
5155		images.getSamplerB(),
5156	};
5157
5158	vk::DescriptorSetLayoutBuilder			builder;
5159	const bool								addSeparateImage	= descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER;
5160	vk::VkDescriptorSetLayoutCreateFlags	extraFlags			= 0;
5161
5162	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
5163			updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5164	{
5165		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
5166	}
5167
5168	// (combined)samplers follow
5169	switch (shaderInterface)
5170	{
5171		case SHADER_INPUT_SINGLE_DESCRIPTOR:
5172			if (addSeparateImage)
5173				builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
5174			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
5175			break;
5176
5177		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5178			if (addSeparateImage)
5179				builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
5180			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
5181			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
5182			break;
5183
5184		case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
5185			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
5186			if (addSeparateImage)
5187				builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
5188			builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
5189			break;
5190
5191		case SHADER_INPUT_DESCRIPTOR_ARRAY:
5192			if (addSeparateImage)
5193				builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
5194			builder.addArraySamplerBinding(descriptorType, 2u, stageFlags, (images.isImmutable()) ? (samplers) : (DE_NULL));
5195			break;
5196
5197		default:
5198			DE_FATAL("Impossible");
5199	}
5200
5201	return builder.build(vki, device, extraFlags);
5202}
5203
5204vk::Move<vk::VkPipelineLayout> ImageSampleRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
5205																				vk::VkDevice				device,
5206																				vk::VkDescriptorSetLayout	descriptorSetLayout)
5207{
5208	const vk::VkPipelineLayoutCreateInfo createInfo =
5209	{
5210		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
5211		DE_NULL,
5212		(vk::VkPipelineLayoutCreateFlags)0,
5213		1,						// descriptorSetCount
5214		&descriptorSetLayout,	// pSetLayouts
5215		0u,						// pushConstantRangeCount
5216		DE_NULL,				// pPushConstantRanges
5217	};
5218	return vk::createPipelineLayout(vki, device, &createInfo);
5219}
5220
5221vk::Move<vk::VkDescriptorPool> ImageSampleRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
5222																				vk::VkDevice				device,
5223																				vk::VkDescriptorType		descriptorType,
5224																				ShaderInputInterface		shaderInterface)
5225{
5226	vk::DescriptorPoolBuilder builder;
5227
5228	if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5229	{
5230		// separate samplers need image to sample
5231		builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
5232
5233		// also need sample to use, indifferent of whether immutable or not
5234		builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLER, getInterfaceNumResources(shaderInterface));
5235	}
5236	else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5237	{
5238		// combined image samplers
5239		builder.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, getInterfaceNumResources(shaderInterface));
5240	}
5241	else
5242		DE_FATAL("Impossible");
5243
5244	return builder.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
5245}
5246
5247vk::Move<vk::VkDescriptorSet> ImageSampleRenderInstance::createDescriptorSet (const vk::DeviceInterface&					vki,
5248																			  DescriptorUpdateMethod						updateMethod,
5249																			  vk::VkDevice									device,
5250																			  vk::VkDescriptorType							descriptorType,
5251																			  ShaderInputInterface							shaderInterface,
5252																			  vk::VkDescriptorSetLayout						layout,
5253																			  vk::VkDescriptorPool							pool,
5254																			  bool											isImmutable,
5255																			  const ImageSampleInstanceImages&				images,
5256																			  vk::DescriptorSetUpdateBuilder&				updateBuilder,
5257																			  vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
5258																			  RawUpdateRegistry&							updateRegistry,
5259																			  vk::VkPipelineLayout							pipelineLayout)
5260{
5261	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
5262	{
5263		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
5264		DE_NULL,
5265		pool,
5266		1u,
5267		&layout
5268	};
5269
5270	vk::Move<vk::VkDescriptorSet>			descriptorSet;
5271	if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
5272	{
5273		descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
5274	}
5275	else
5276	{
5277		descriptorSet = vk::Move<vk::VkDescriptorSet>();
5278	}
5279
5280	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
5281	{
5282		if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5283			writeSamplerDescriptorSetWithTemplate(vki, device,  shaderInterface, isImmutable, images, *descriptorSet, layout, updateTemplate, updateRegistry);
5284		else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5285			writeImageSamplerDescriptorSetWithTemplate(vki, device, shaderInterface, isImmutable, images, *descriptorSet, layout, updateTemplate, updateRegistry);
5286		else
5287			DE_FATAL("Impossible");
5288	}
5289	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
5290	{
5291		if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5292			writeSamplerDescriptorSetWithTemplate(vki, device,  shaderInterface, isImmutable, images, DE_NULL, layout, updateTemplate, updateRegistry, true, pipelineLayout);
5293		else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5294			writeImageSamplerDescriptorSetWithTemplate(vki, device, shaderInterface, isImmutable, images, DE_NULL, layout, updateTemplate, updateRegistry, true, pipelineLayout);
5295		else
5296			DE_FATAL("Impossible");
5297	}
5298	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5299	{
5300		if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5301			writeSamplerDescriptorSet(vki, device,  shaderInterface, isImmutable, images, *descriptorSet, updateBuilder, updateMethod);
5302		else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5303			writeImageSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, updateBuilder, updateMethod);
5304		else
5305			DE_FATAL("Impossible");
5306	}
5307	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
5308	{
5309		if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5310			writeSamplerDescriptorSet(vki, device,  shaderInterface, isImmutable, images, *descriptorSet, updateBuilder);
5311		else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5312			writeImageSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, updateBuilder);
5313		else
5314			DE_FATAL("Impossible");
5315	}
5316
5317	return descriptorSet;
5318}
5319
5320void ImageSampleRenderInstance::writeSamplerDescriptorSet (const vk::DeviceInterface&		vki,
5321														   vk::VkDevice						device,
5322														   ShaderInputInterface				shaderInterface,
5323														   bool								isImmutable,
5324														   const ImageSampleInstanceImages&	images,
5325														   vk::VkDescriptorSet				descriptorSet,
5326														   vk::DescriptorSetUpdateBuilder&	updateBuilder,
5327														   DescriptorUpdateMethod			updateMethod)
5328{
5329	const vk::VkDescriptorImageInfo		imageInfo			= makeDescriptorImageInfo(images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
5330	const vk::VkDescriptorImageInfo		samplersInfos[2]	=
5331	{
5332		makeDescriptorImageInfo(images.getSamplerA()),
5333		makeDescriptorImageInfo(images.getSamplerB()),
5334	};
5335
5336	const deUint32						samplerLocation		= shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS ? 1u : 0u;
5337
5338	// stand alone texture
5339	updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(samplerLocation), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
5340
5341	// samplers
5342	if (!isImmutable || (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH))
5343	{
5344		switch (shaderInterface)
5345		{
5346			case SHADER_INPUT_SINGLE_DESCRIPTOR:
5347				updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
5348				break;
5349
5350			case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5351				updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
5352				updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
5353				break;
5354
5355			case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
5356				updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
5357				updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
5358				break;
5359
5360			case SHADER_INPUT_DESCRIPTOR_ARRAY:
5361				updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
5362				break;
5363
5364			default:
5365				DE_FATAL("Impossible");
5366		}
5367	}
5368
5369	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
5370	{
5371		updateBuilder.update(vki, device);
5372	}
5373}
5374
5375void ImageSampleRenderInstance::writeImageSamplerDescriptorSet (const vk::DeviceInterface&			vki,
5376																vk::VkDevice						device,
5377																ShaderInputInterface				shaderInterface,
5378																bool								isImmutable,
5379																const ImageSampleInstanceImages&	images,
5380																vk::VkDescriptorSet					descriptorSet,
5381																vk::DescriptorSetUpdateBuilder&		updateBuilder,
5382																DescriptorUpdateMethod				updateMethod)
5383{
5384	const vk::VkSampler					samplers[2]			=
5385	{
5386		(isImmutable && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? (0) : (images.getSamplerA()),
5387		(isImmutable && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? (0) : (images.getSamplerB()),
5388	};
5389	const vk::VkDescriptorImageInfo		imageSamplers[2]	=
5390	{
5391		vk::makeDescriptorImageInfo(samplers[0], images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
5392		vk::makeDescriptorImageInfo(samplers[1], images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
5393	};
5394
5395	// combined image samplers
5396	switch (shaderInterface)
5397	{
5398		case SHADER_INPUT_SINGLE_DESCRIPTOR:
5399			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
5400			break;
5401
5402		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5403			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
5404			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
5405			break;
5406
5407		case SHADER_INPUT_DESCRIPTOR_ARRAY:
5408			updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
5409			break;
5410
5411		default:
5412			DE_FATAL("Impossible");
5413	}
5414
5415	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
5416	{
5417		updateBuilder.update(vki, device);
5418	}
5419}
5420
5421void ImageSampleRenderInstance::writeSamplerDescriptorSetWithTemplate (const vk::DeviceInterface&					vki,
5422																	   vk::VkDevice									device,
5423																	   ShaderInputInterface							shaderInterface,
5424																	   bool											isImmutable,
5425																	   const ImageSampleInstanceImages&				images,
5426																	   vk::VkDescriptorSet							descriptorSet,
5427																	   vk::VkDescriptorSetLayout					layout,
5428																	   vk::Move<vk::VkDescriptorUpdateTemplate>&	updateTemplate,
5429																	   RawUpdateRegistry&							updateRegistry,
5430																	   bool											withPush,
5431																	   vk::VkPipelineLayout							pipelineLayout)
5432{
5433	const vk::VkDescriptorImageInfo							imageInfo			= makeDescriptorImageInfo(images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
5434	const vk::VkDescriptorImageInfo							samplersInfos[2]	=
5435	{
5436		makeDescriptorImageInfo(images.getSamplerA()),
5437		makeDescriptorImageInfo(images.getSamplerB()),
5438	};
5439
5440	const deUint32											samplerLocation		= shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS ? 1u : 0u;
5441
5442	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
5443	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
5444	{
5445		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
5446		DE_NULL,
5447		0,
5448		0,			// updateCount
5449		DE_NULL,	// pUpdates
5450		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
5451		layout,
5452		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
5453		pipelineLayout,
5454		0
5455	};
5456	updateRegistry.addWriteObject(imageInfo);
5457	updateRegistry.addWriteObject(samplersInfos[0]);
5458	updateRegistry.addWriteObject(samplersInfos[1]);
5459
5460	// stand alone texture
5461	updateEntries.push_back(createTemplateBinding(samplerLocation, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, updateRegistry.getWriteObjectOffset(0), 0));
5462
5463	// samplers
5464	if (!isImmutable || withPush)
5465	{
5466		switch (shaderInterface)
5467		{
5468			case SHADER_INPUT_SINGLE_DESCRIPTOR:
5469				updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
5470				break;
5471
5472			case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5473				updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
5474				updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(2), 0));
5475				break;
5476
5477			case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
5478				updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
5479				updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(2), 0));
5480				break;
5481
5482			case SHADER_INPUT_DESCRIPTOR_ARRAY:
5483				updateEntries.push_back(createTemplateBinding(1, 0, 2, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), sizeof(samplersInfos[0])));
5484				break;
5485
5486			default:
5487				DE_FATAL("Impossible");
5488		}
5489	}
5490
5491	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
5492	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
5493
5494	updateTemplate									= vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
5495
5496	if (!withPush)
5497	{
5498		vki.updateDescriptorSetWithTemplate(device, descriptorSet, *updateTemplate, updateRegistry.getRawPointer());
5499	}
5500
5501}
5502
5503void ImageSampleRenderInstance::writeImageSamplerDescriptorSetWithTemplate (const vk::DeviceInterface&						vki,
5504																			vk::VkDevice									device,
5505																			ShaderInputInterface							shaderInterface,
5506																			bool											isImmutable,
5507																			const ImageSampleInstanceImages&				images,
5508																			vk::VkDescriptorSet								descriptorSet,
5509																			vk::VkDescriptorSetLayout						layout,
5510																			vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
5511																			RawUpdateRegistry&								updateRegistry,
5512																			bool											withPush,
5513																			vk::VkPipelineLayout							pipelineLayout)
5514{
5515	const vk::VkSampler					samplers[2]			=
5516	{
5517		(isImmutable && !withPush) ? (0) : (images.getSamplerA()),
5518		(isImmutable && !withPush) ? (0) : (images.getSamplerB()),
5519	};
5520	const vk::VkDescriptorImageInfo		imageSamplers[2]	=
5521	{
5522		vk::makeDescriptorImageInfo(samplers[0], images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
5523		vk::makeDescriptorImageInfo(samplers[1], images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
5524	};
5525
5526	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
5527	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
5528	{
5529		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
5530		DE_NULL,
5531		0,
5532		0,			// updateCount
5533		DE_NULL,	// pUpdates
5534		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
5535		layout,
5536		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
5537		pipelineLayout,
5538		0
5539	};
5540	updateRegistry.addWriteObject(imageSamplers[0]);
5541	updateRegistry.addWriteObject(imageSamplers[1]);
5542
5543	// combined image samplers
5544	switch (shaderInterface)
5545	{
5546		case SHADER_INPUT_SINGLE_DESCRIPTOR:
5547			updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
5548			break;
5549
5550		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5551			updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
5552			updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
5553			break;
5554
5555		case SHADER_INPUT_DESCRIPTOR_ARRAY:
5556			updateEntries.push_back(createTemplateBinding(0, 0, 2, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), sizeof(imageSamplers[0])));
5557			break;
5558
5559		default:
5560			DE_FATAL("Impossible");
5561	}
5562
5563	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
5564	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
5565
5566	updateTemplate									= vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
5567
5568	if (!withPush)
5569	{
5570		vki.updateDescriptorSetWithTemplate(device, descriptorSet, *updateTemplate, updateRegistry.getRawPointer());
5571	}
5572}
5573
5574void ImageSampleRenderInstance::logTestPlan (void) const
5575{
5576	std::ostringstream msg;
5577
5578	msg << "Rendering 2x2 grid.\n";
5579
5580	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5581	{
5582		msg << "Single descriptor set. Descriptor set contains "
5583			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
5584			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
5585				(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
5586			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
5587			    (const char*)DE_NULL)
5588			<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
5589	}
5590	else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5591	{
5592		msg << "Single descriptor set. Descriptor set contains "
5593			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
5594			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
5595				(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
5596			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
5597			    (const char*)DE_NULL)
5598			<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
5599	}
5600	else
5601		DE_FATAL("Impossible");
5602
5603	msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
5604
5605	if (m_baseMipLevel)
5606		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
5607	if (m_baseArraySlice)
5608		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
5609
5610	if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
5611		msg << "Sampler mode is LINEAR, with WRAP\n";
5612	else
5613		msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
5614
5615	if (m_stageFlags == 0u)
5616	{
5617		msg << "Descriptors are not accessed in any shader stage.\n";
5618	}
5619	else
5620	{
5621		msg << "Color in each cell is fetched using the descriptor(s):\n";
5622
5623		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
5624		{
5625			msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
5626
5627			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
5628			{
5629				const int srcResourceNdx = (resultNdx % 2); // ABAB source
5630
5631				if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5632					msg << " using sampler " << srcResourceNdx;
5633				else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5634					msg << " from combined image sampler " << srcResourceNdx;
5635				else
5636					DE_FATAL("Impossible");
5637			}
5638			msg << "\n";
5639		}
5640
5641		msg << "Descriptors are accessed in {"
5642			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)					? (" vertex")			: (""))
5643			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
5644			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
5645			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)				? (" geometry")			: (""))
5646			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)				? (" fragment")			: (""))
5647			<< " } stages.";
5648	}
5649
5650	m_context.getTestContext().getLog()
5651		<< tcu::TestLog::Message
5652		<< msg.str()
5653		<< tcu::TestLog::EndMessage;
5654}
5655
5656vk::VkPipelineLayout ImageSampleRenderInstance::getPipelineLayout (void) const
5657{
5658	return *m_pipelineLayout;
5659}
5660
5661void ImageSampleRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
5662{
5663	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5664	{
5665		m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0u, 1u, &m_descriptorSet.get(), 0u, DE_NULL);
5666	}
5667	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
5668	{
5669		m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, *m_updateTemplate, getPipelineLayout(), 0, (const void*)m_updateRegistry.getRawPointer());
5670	}
5671	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5672	{
5673		m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0);
5674	}
5675
5676	m_vki.cmdDraw(cmd, 6u * 4u, 1u, 0u, 0u); // render four quads (two separate triangles)
5677}
5678
5679tcu::TestStatus ImageSampleRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
5680{
5681	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
5682	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
5683	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
5684	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_images.fetchSampleValue(0));
5685	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_images.fetchSampleValue(1));
5686	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_images.fetchSampleValue(2));
5687	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_images.fetchSampleValue(3));
5688	const tcu::RGBA		threshold	= tcu::RGBA(8, 8, 8, 8); // source image is high-frequency so the threshold is quite large to tolerate sampling errors
5689	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
5690
5691	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
5692
5693	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, threshold, tcu::COMPARE_LOG_RESULT))
5694		return tcu::TestStatus::fail("Image verification failed");
5695	else
5696		return tcu::TestStatus::pass("Pass");
5697}
5698
5699class ImageSampleComputeInstance : public vkt::TestInstance
5700{
5701public:
5702											ImageSampleComputeInstance					(vkt::Context&			context,
5703																						 DescriptorUpdateMethod	updateMethod,
5704																						 vk::VkDescriptorType	descriptorType,
5705																						 ShaderInputInterface	shaderInterface,
5706																						 vk::VkImageViewType	viewType,
5707																						 deUint32				baseMipLevel,
5708																						 deUint32				baseArraySlice,
5709																						 bool					isImmutableSampler);
5710
5711private:
5712	vk::Move<vk::VkDescriptorSetLayout>			createDescriptorSetLayout					(void) const;
5713	vk::Move<vk::VkDescriptorPool>				createDescriptorPool						(void) const;
5714	vk::Move<vk::VkDescriptorSet>				createDescriptorSet							(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout);
5715	void										writeDescriptorSet							(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, vk::VkPipelineLayout pipelineLayout = DE_NULL);
5716	void										writeImageSamplerDescriptorSet				(vk::VkDescriptorSet descriptorSet);
5717	void										writeImageSamplerDescriptorSetWithTemplate	(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
5718	void										writeSamplerDescriptorSet					(vk::VkDescriptorSet descriptorSet);
5719	void										writeSamplerDescriptorSetWithTemplate		(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
5720
5721	tcu::TestStatus								iterate										(void);
5722	void										logTestPlan									(void) const;
5723	tcu::TestStatus								testResourceAccess							(void);
5724
5725	const DescriptorUpdateMethod				m_updateMethod;
5726	const vk::VkDescriptorType					m_descriptorType;
5727	const ShaderInputInterface					m_shaderInterface;
5728	const vk::VkImageViewType					m_viewType;
5729	const deUint32								m_baseMipLevel;
5730	const deUint32								m_baseArraySlice;
5731	const bool									m_isImmutableSampler;
5732	vk::Move<vk::VkDescriptorUpdateTemplate>	m_updateTemplate;
5733
5734	const vk::DeviceInterface&					m_vki;
5735	const vk::VkDevice							m_device;
5736	const vk::VkQueue							m_queue;
5737	const deUint32								m_queueFamilyIndex;
5738	vk::Allocator&								m_allocator;
5739
5740	const ComputeInstanceResultBuffer			m_result;
5741	const ImageSampleInstanceImages				m_images;
5742
5743	RawUpdateRegistry							m_updateRegistry;
5744	vk::DescriptorSetUpdateBuilder				m_updateBuilder;
5745};
5746
5747ImageSampleComputeInstance::ImageSampleComputeInstance (Context&				context,
5748														DescriptorUpdateMethod	updateMethod,
5749														vk::VkDescriptorType	descriptorType,
5750														ShaderInputInterface	shaderInterface,
5751														vk::VkImageViewType		viewType,
5752														deUint32				baseMipLevel,
5753														deUint32				baseArraySlice,
5754														bool					isImmutableSampler)
5755	: vkt::TestInstance		(context)
5756	, m_updateMethod		(updateMethod)
5757	, m_descriptorType		(descriptorType)
5758	, m_shaderInterface		(shaderInterface)
5759	, m_viewType			(viewType)
5760	, m_baseMipLevel		(baseMipLevel)
5761	, m_baseArraySlice		(baseArraySlice)
5762	, m_isImmutableSampler	(isImmutableSampler)
5763	, m_updateTemplate		()
5764	, m_vki					(context.getDeviceInterface())
5765	, m_device				(context.getDevice())
5766	, m_queue				(context.getUniversalQueue())
5767	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
5768	, m_allocator			(context.getDefaultAllocator())
5769	, m_result				(m_vki, m_device, m_allocator)
5770	, m_images				(m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutableSampler)
5771	, m_updateRegistry		()
5772	, m_updateBuilder		()
5773{
5774}
5775
5776vk::Move<vk::VkDescriptorSetLayout> ImageSampleComputeInstance::createDescriptorSetLayout (void) const
5777{
5778	const vk::VkSampler						samplers[2] =
5779	{
5780		m_images.getSamplerA(),
5781		m_images.getSamplerB(),
5782	};
5783
5784	vk::DescriptorSetLayoutBuilder			builder;
5785	vk::VkDescriptorSetLayoutCreateFlags	extraFlags = 0;
5786
5787	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
5788			m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5789	{
5790		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
5791	}
5792
5793	// result buffer
5794	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
5795
5796	// with samplers, separate texture at binding 0
5797	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5798		builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
5799
5800	// (combined)samplers follow
5801	switch (m_shaderInterface)
5802	{
5803		case SHADER_INPUT_SINGLE_DESCRIPTOR:
5804			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
5805			break;
5806
5807		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5808			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
5809			builder.addSingleSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
5810			break;
5811
5812		case SHADER_INPUT_DESCRIPTOR_ARRAY:
5813			builder.addArraySamplerBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (samplers) : (DE_NULL));
5814			break;
5815
5816		default:
5817			DE_FATAL("Impossible");
5818	};
5819
5820	return builder.build(m_vki, m_device, extraFlags);
5821}
5822
5823vk::Move<vk::VkDescriptorPool> ImageSampleComputeInstance::createDescriptorPool (void) const
5824{
5825	vk::DescriptorPoolBuilder builder;
5826
5827	builder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
5828	builder.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface));
5829
5830	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5831		builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
5832
5833	return builder.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
5834}
5835
5836vk::Move<vk::VkDescriptorSet> ImageSampleComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout)
5837{
5838	const vk::VkDescriptorSetAllocateInfo	allocInfo		=
5839	{
5840		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
5841		DE_NULL,
5842		pool,
5843		1u,
5844		&layout
5845	};
5846
5847	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5848	{
5849		vk::Move<vk::VkDescriptorSet>			descriptorSet	= allocateDescriptorSet(m_vki, m_device, &allocInfo);
5850		writeDescriptorSet(*descriptorSet, layout);
5851
5852		return descriptorSet;
5853	}
5854
5855	return vk::Move<vk::VkDescriptorSet>();
5856}
5857
5858void ImageSampleComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, vk::VkPipelineLayout pipelineLayout)
5859{
5860	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
5861	{
5862		if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5863			writeSamplerDescriptorSetWithTemplate(descriptorSet, layout);
5864		else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5865			writeImageSamplerDescriptorSetWithTemplate(descriptorSet, layout);
5866		else
5867			DE_FATAL("Impossible");
5868	}
5869	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
5870	{
5871		if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5872			writeSamplerDescriptorSetWithTemplate(descriptorSet, layout, true, pipelineLayout);
5873		else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5874			writeImageSamplerDescriptorSetWithTemplate(descriptorSet, layout, true, pipelineLayout);
5875		else
5876			DE_FATAL("Impossible");
5877	}
5878	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
5879	{
5880		if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5881			writeSamplerDescriptorSet(descriptorSet);
5882		else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5883			writeImageSamplerDescriptorSet(descriptorSet);
5884		else
5885			DE_FATAL("Impossible");
5886	}
5887	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
5888	{
5889		if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
5890			writeSamplerDescriptorSet(descriptorSet);
5891		else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
5892			writeImageSamplerDescriptorSet(descriptorSet);
5893		else
5894			DE_FATAL("Impossible");
5895	}
5896}
5897
5898void ImageSampleComputeInstance::writeSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet)
5899{
5900	const vk::VkDescriptorBufferInfo	resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
5901	const vk::VkDescriptorImageInfo		imageInfo			= makeDescriptorImageInfo(m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
5902	const vk::VkDescriptorImageInfo		samplersInfos[2]	=
5903	{
5904		makeDescriptorImageInfo(m_images.getSamplerA()),
5905		makeDescriptorImageInfo(m_images.getSamplerB()),
5906	};
5907
5908	// result
5909	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
5910
5911	// stand alone texture
5912	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
5913
5914	// samplers
5915	if (!m_isImmutableSampler || (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH))
5916	{
5917		switch (m_shaderInterface)
5918		{
5919			case SHADER_INPUT_SINGLE_DESCRIPTOR:
5920				m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
5921				break;
5922
5923			case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5924				m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
5925				m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(3u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
5926				break;
5927
5928			case SHADER_INPUT_DESCRIPTOR_ARRAY:
5929				m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
5930				break;
5931
5932			default:
5933				DE_FATAL("Impossible");
5934		}
5935	}
5936
5937	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
5938	{
5939		m_updateBuilder.update(m_vki, m_device);
5940	}
5941}
5942
5943void ImageSampleComputeInstance::writeSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush, vk::VkPipelineLayout pipelineLayout)
5944{
5945	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
5946	const vk::VkDescriptorBufferInfo						resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
5947	const vk::VkDescriptorImageInfo							imageInfo			= makeDescriptorImageInfo(m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
5948	const vk::VkDescriptorImageInfo							samplersInfos[2]	=
5949	{
5950		makeDescriptorImageInfo(m_images.getSamplerA()),
5951		makeDescriptorImageInfo(m_images.getSamplerB()),
5952	};
5953	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
5954	{
5955		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
5956		DE_NULL,
5957		0,
5958		0,			// updateCount
5959		DE_NULL,	// pUpdates
5960		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
5961		layout,
5962		vk::VK_PIPELINE_BIND_POINT_COMPUTE,
5963		pipelineLayout,
5964		0
5965	};
5966	m_updateRegistry.addWriteObject(resultInfo);
5967	m_updateRegistry.addWriteObject(imageInfo);
5968	m_updateRegistry.addWriteObject(samplersInfos[0]);
5969	m_updateRegistry.addWriteObject(samplersInfos[1]);
5970
5971	// result
5972	updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_updateRegistry.getWriteObjectOffset(0), 0));
5973	// stand alone texture
5974	updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, m_updateRegistry.getWriteObjectOffset(1), 0));
5975
5976	// samplers
5977	if (!m_isImmutableSampler || withPush)
5978	{
5979		switch (m_shaderInterface)
5980		{
5981			case SHADER_INPUT_SINGLE_DESCRIPTOR:
5982				updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, m_updateRegistry.getWriteObjectOffset(2), 0));
5983				break;
5984
5985			case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
5986				updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, m_updateRegistry.getWriteObjectOffset(2), 0));
5987				updateEntries.push_back(createTemplateBinding(3, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, m_updateRegistry.getWriteObjectOffset(3), 0));
5988				break;
5989
5990			case SHADER_INPUT_DESCRIPTOR_ARRAY:
5991				updateEntries.push_back(createTemplateBinding(2, 0, 2, vk::VK_DESCRIPTOR_TYPE_SAMPLER, m_updateRegistry.getWriteObjectOffset(2), sizeof(samplersInfos[0])));
5992				break;
5993
5994			default:
5995				DE_FATAL("Impossible");
5996		}
5997	}
5998
5999	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
6000	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
6001
6002	m_updateTemplate								= vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
6003
6004	if (!withPush)
6005	{
6006		m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, *m_updateTemplate, m_updateRegistry.getRawPointer());
6007	}
6008}
6009
6010void ImageSampleComputeInstance::writeImageSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet)
6011{
6012	const vk::VkDescriptorBufferInfo	resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
6013	const vk::VkSampler					samplers[2]			=
6014	{
6015		(m_isImmutableSampler && (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)) ? (0) : (m_images.getSamplerA()),
6016		(m_isImmutableSampler && (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)) ? (0) : (m_images.getSamplerB()),
6017	};
6018	const vk::VkDescriptorImageInfo		imageSamplers[2]	=
6019	{
6020		makeDescriptorImageInfo(samplers[0], m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
6021		makeDescriptorImageInfo(samplers[1], m_images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
6022	};
6023
6024	// result
6025	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
6026
6027	// combined image samplers
6028	switch (m_shaderInterface)
6029	{
6030		case SHADER_INPUT_SINGLE_DESCRIPTOR:
6031			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
6032			break;
6033
6034		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
6035			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
6036			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
6037			break;
6038
6039		case SHADER_INPUT_DESCRIPTOR_ARRAY:
6040			m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
6041			break;
6042
6043		default:
6044			DE_FATAL("Impossible");
6045	}
6046
6047	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
6048	{
6049		m_updateBuilder.update(m_vki, m_device);
6050	}
6051}
6052
6053void ImageSampleComputeInstance::writeImageSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush, vk::VkPipelineLayout pipelineLayout)
6054{
6055	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
6056	const vk::VkDescriptorBufferInfo						resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
6057	const vk::VkSampler										samplers[2]			=
6058	{
6059		(m_isImmutableSampler && !withPush) ? (0) : (m_images.getSamplerA()),
6060		(m_isImmutableSampler && !withPush) ? (0) : (m_images.getSamplerB()),
6061	};
6062	const vk::VkDescriptorImageInfo							imageSamplers[2]	=
6063	{
6064		makeDescriptorImageInfo(samplers[0], m_images.getImageViewA(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
6065		makeDescriptorImageInfo(samplers[1], m_images.getImageViewB(), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
6066	};
6067	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
6068	{
6069		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
6070		DE_NULL,
6071		0,
6072		0,			// updateCount
6073		DE_NULL,	// pUpdates
6074		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
6075		layout,
6076		vk::VK_PIPELINE_BIND_POINT_COMPUTE,
6077		pipelineLayout,
6078		0
6079	};
6080	m_updateRegistry.addWriteObject(resultInfo);
6081	m_updateRegistry.addWriteObject(imageSamplers[0]);
6082	m_updateRegistry.addWriteObject(imageSamplers[1]);
6083
6084	// result
6085	updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_updateRegistry.getWriteObjectOffset(0), 0));
6086
6087	// combined image samplers
6088	switch (m_shaderInterface)
6089	{
6090		case SHADER_INPUT_SINGLE_DESCRIPTOR:
6091			updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_updateRegistry.getWriteObjectOffset(1), 0));
6092			break;
6093
6094		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
6095			updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_updateRegistry.getWriteObjectOffset(1), 0));
6096			updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_updateRegistry.getWriteObjectOffset(2), 0));
6097			break;
6098
6099		case SHADER_INPUT_DESCRIPTOR_ARRAY:
6100			updateEntries.push_back(createTemplateBinding(1, 0, 2, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, m_updateRegistry.getWriteObjectOffset(1), sizeof(imageSamplers[0])));
6101			break;
6102
6103		default:
6104			DE_FATAL("Impossible");
6105	}
6106
6107	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
6108	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
6109
6110	m_updateTemplate								= vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
6111
6112	if (!withPush)
6113	{
6114		m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, *m_updateTemplate, m_updateRegistry.getRawPointer());
6115	}
6116}
6117
6118tcu::TestStatus ImageSampleComputeInstance::iterate (void)
6119{
6120	logTestPlan();
6121	return testResourceAccess();
6122}
6123
6124void ImageSampleComputeInstance::logTestPlan (void) const
6125{
6126	std::ostringstream msg;
6127
6128	msg << "Accessing resource in a compute program.\n";
6129
6130	if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
6131	{
6132		msg << "Single descriptor set. Descriptor set contains "
6133			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
6134			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
6135			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
6136			    (const char*)DE_NULL)
6137			<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
6138	}
6139	else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
6140	{
6141		msg << "Single descriptor set. Descriptor set contains "
6142			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
6143			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
6144			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
6145			    (const char*)DE_NULL)
6146			<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
6147	}
6148	else
6149		DE_FATAL("Impossible");
6150
6151	msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
6152
6153	if (m_baseMipLevel)
6154		msg << "Image view base mip level = " << m_baseMipLevel << "\n";
6155	if (m_baseArraySlice)
6156		msg << "Image view base array slice = " << m_baseArraySlice << "\n";
6157
6158	if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
6159		msg << "Sampler mode is LINEAR, with WRAP\n";
6160	else
6161		msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
6162
6163	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
6164	{
6165		msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
6166
6167		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
6168		{
6169			const int srcResourceNdx = (resultNdx % 2); // ABAB source
6170
6171			if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
6172				msg << " using sampler " << srcResourceNdx;
6173			else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
6174				msg << " from combined image sampler " << srcResourceNdx;
6175			else
6176				DE_FATAL("Impossible");
6177		}
6178		msg << "\n";
6179	}
6180
6181	m_context.getTestContext().getLog()
6182		<< tcu::TestLog::Message
6183		<< msg.str()
6184		<< tcu::TestLog::EndMessage;
6185}
6186
6187tcu::TestStatus ImageSampleComputeInstance::testResourceAccess (void)
6188{
6189	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
6190	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
6191	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
6192	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
6193
6194	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
6195	const int										numDescriptorSets	= (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE || m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? 0 : DE_LENGTH_OF_ARRAY(descriptorSets);
6196	const deUint32* const							dynamicOffsets		= DE_NULL;
6197	const int										numDynamicOffsets	= 0;
6198	const vk::VkBufferMemoryBarrier* const			preBarriers			= DE_NULL;
6199	const int										numPreBarriers		= 0;
6200	const vk::VkBufferMemoryBarrier* const			postBarriers		= m_result.getResultReadBarrier();
6201	const int										numPostBarriers		= 1;
6202
6203	const ComputeCommand							compute				(m_vki,
6204																		 m_device,
6205																		 pipeline.getPipeline(),
6206																		 pipeline.getPipelineLayout(),
6207																		 tcu::UVec3(4, 1, 1),
6208																		 numDescriptorSets,	descriptorSets,
6209																		 numDynamicOffsets,	dynamicOffsets,
6210																		 numPreBarriers,	preBarriers,
6211																		 numPostBarriers,	postBarriers);
6212
6213	tcu::Vec4										results[4];
6214	bool											anyResultSet		= false;
6215	bool											allResultsOk		= true;
6216
6217	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
6218	{
6219		writeDescriptorSet(DE_NULL, *descriptorSetLayout, pipeline.getPipelineLayout()); // descriptor set not applicable
6220		compute.submitAndWait(m_queueFamilyIndex, m_queue, *m_updateTemplate, (void *) m_updateRegistry.getRawPointer());
6221	}
6222	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
6223	{
6224		writeDescriptorSet(DE_NULL, *descriptorSetLayout, pipeline.getPipelineLayout()); // descriptor set not applicable
6225		compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder);
6226	}
6227	else
6228	{
6229		compute.submitAndWait(m_queueFamilyIndex, m_queue);
6230	}
6231	m_result.readResultContentsTo(&results);
6232
6233	// verify
6234	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
6235	{
6236		const tcu::Vec4	result				= results[resultNdx];
6237		const tcu::Vec4	reference			= m_images.fetchSampleValue(resultNdx);
6238
6239		// source image is high-frequency so the threshold is quite large to tolerate sampling errors
6240		const tcu::Vec4	samplingThreshold	= tcu::Vec4(8.0f / 255.0f);
6241
6242		if (result != tcu::Vec4(-1.0f))
6243			anyResultSet = true;
6244
6245		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), samplingThreshold)))
6246		{
6247			allResultsOk = false;
6248
6249			m_context.getTestContext().getLog()
6250				<< tcu::TestLog::Message
6251				<< "Test sample " << resultNdx << ":\n"
6252				<< "\tSampling at " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx) << "\n"
6253				<< "\tError expected " << reference << ", got " << result
6254				<< tcu::TestLog::EndMessage;
6255		}
6256	}
6257
6258	// read back and verify
6259	if (allResultsOk)
6260		return tcu::TestStatus::pass("Pass");
6261	else if (anyResultSet)
6262		return tcu::TestStatus::fail("Invalid result values");
6263	else
6264	{
6265		m_context.getTestContext().getLog()
6266			<< tcu::TestLog::Message
6267			<< "Result buffer was not written to."
6268			<< tcu::TestLog::EndMessage;
6269		return tcu::TestStatus::fail("Result buffer was not written to");
6270	}
6271}
6272
6273class ImageDescriptorCase : public QuadrantRendederCase
6274{
6275public:
6276	enum
6277	{
6278		FLAG_BASE_MIP	= (1u << 1u),
6279		FLAG_BASE_SLICE	= (1u << 2u),
6280	};
6281	// enum continues where resource flags ends
6282	DE_STATIC_ASSERT((deUint32)FLAG_BASE_MIP == (deUint32)RESOURCE_FLAG_LAST);
6283
6284								ImageDescriptorCase			(tcu::TestContext&		testCtx,
6285															 const char*			name,
6286															 const char*			description,
6287															 bool					isPrimaryCmdBuf,
6288															 DescriptorUpdateMethod updateMethod,
6289															 vk::VkDescriptorType	descriptorType,
6290															 vk::VkShaderStageFlags	exitingStages,
6291															 vk::VkShaderStageFlags	activeStages,
6292															 ShaderInputInterface	shaderInterface,
6293															 vk::VkImageViewType	viewType,
6294															 deUint32				flags);
6295
6296private:
6297	std::string					genExtensionDeclarations	(vk::VkShaderStageFlagBits stage) const;
6298	std::string					genResourceDeclarations		(vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
6299	std::string					genFetchCoordStr			(int fetchPosNdx) const;
6300	std::string					genSampleCoordStr			(int samplePosNdx) const;
6301	std::string					genResourceAccessSource		(vk::VkShaderStageFlagBits stage) const;
6302	std::string					genNoAccessSource			(void) const;
6303
6304	vkt::TestInstance*			createInstance				(vkt::Context& context) const;
6305
6306private:
6307	const bool						m_isPrimaryCmdBuf;
6308	const DescriptorUpdateMethod	m_updateMethod;
6309	const vk::VkDescriptorType		m_descriptorType;
6310	const ShaderInputInterface		m_shaderInterface;
6311	const vk::VkImageViewType		m_viewType;
6312	const deUint32					m_baseMipLevel;
6313	const deUint32					m_baseArraySlice;
6314	const bool						m_isImmutableSampler;
6315};
6316
6317ImageDescriptorCase::ImageDescriptorCase (tcu::TestContext&			testCtx,
6318										  const char*				name,
6319										  const char*				description,
6320										  bool						isPrimaryCmdBuf,
6321										  DescriptorUpdateMethod	updateMethod,
6322										  vk::VkDescriptorType		descriptorType,
6323										  vk::VkShaderStageFlags	exitingStages,
6324										  vk::VkShaderStageFlags	activeStages,
6325										  ShaderInputInterface		shaderInterface,
6326										  vk::VkImageViewType		viewType,
6327										  deUint32					flags)
6328	: QuadrantRendederCase	(testCtx, name, description,
6329							 // \note 1D textures are not supported in ES
6330							 (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? glu::GLSL_VERSION_440 : glu::GLSL_VERSION_310_ES,
6331							 exitingStages, activeStages)
6332	, m_isPrimaryCmdBuf		(isPrimaryCmdBuf)
6333	, m_updateMethod		(updateMethod)
6334	, m_descriptorType		(descriptorType)
6335	, m_shaderInterface		(shaderInterface)
6336	, m_viewType			(viewType)
6337	, m_baseMipLevel		(((flags & FLAG_BASE_MIP) != 0) ? (1u) : (0u))
6338	, m_baseArraySlice		(((flags & FLAG_BASE_SLICE) != 0) ? (1u) : (0u))
6339	, m_isImmutableSampler	((flags & RESOURCE_FLAG_IMMUTABLE_SAMPLER) != 0)
6340{
6341}
6342
6343std::string ImageDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
6344{
6345	DE_UNREF(stage);
6346
6347	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
6348		return "#extension GL_OES_texture_cube_map_array : require\n";
6349	else
6350		return "";
6351}
6352
6353std::string ImageDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
6354{
6355	DE_UNREF(stage);
6356
6357	// Vulkan-style resources are arrays implicitly, OpenGL-style are not
6358	const std::string	dimensionBase	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? ("1D")
6359										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? ("2D")
6360										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? ("3D")
6361										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("Cube")
6362										: (DE_NULL);
6363	const std::string	dimensionArray	= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)		? ("1DArray")
6364										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)		? ("2DArray")
6365										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)															? ("3D")
6366										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("CubeArray")
6367										: (DE_NULL);
6368	const std::string	dimension		= isImageViewTypeArray(m_viewType) ? dimensionArray : dimensionBase;
6369
6370	if (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS)
6371		DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER);
6372
6373	switch (m_shaderInterface)
6374	{
6375		case SHADER_INPUT_SINGLE_DESCRIPTOR:
6376		{
6377			switch (m_descriptorType)
6378			{
6379				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
6380					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimension + " u_separateTexture;\n"
6381						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSampler;\n";
6382				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6383					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler;\n";
6384				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6385					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture;\n";
6386				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6387					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_image;\n";
6388				default:
6389					DE_FATAL("invalid descriptor");
6390					return "";
6391			}
6392		}
6393
6394		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
6395		case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
6396			switch (m_descriptorType)
6397			{
6398				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
6399					if (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)
6400						return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimension + " u_separateTexture;\n"
6401								"layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSamplerA;\n"
6402								"layout(set = 0, binding = " + de::toString(numUsedBindings+2) + ") uniform highp sampler u_separateSamplerB;\n";
6403					else
6404						return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler u_separateSamplerA;\n"
6405								"layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp texture" + dimension + " u_separateTexture;\n"
6406								"layout(set = 0, binding = " + de::toString(numUsedBindings+2) + ") uniform highp sampler u_separateSamplerB;\n";
6407				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6408					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSamplerA;\n"
6409						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler" + dimension + " u_combinedTextureSamplerB;\n";
6410				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6411					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTextureA;\n"
6412						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp texture" + dimensionBase + " u_separateTextureB;\n";
6413				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6414					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_imageA;\n"
6415						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ", rgba8) readonly uniform highp image" + dimension + " u_imageB;\n";
6416				default:
6417					DE_FATAL("invalid descriptor");
6418					return "";
6419			}
6420
6421		case SHADER_INPUT_DESCRIPTOR_ARRAY:
6422			switch (m_descriptorType)
6423			{
6424				case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
6425					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimension + " u_separateTexture;\n"
6426						   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + ") uniform highp sampler u_separateSampler[2];\n";
6427				case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6428					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler[2];\n";
6429				case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6430					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ") uniform highp texture" + dimensionBase + " u_separateTexture[2];\n";
6431				case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6432					return "layout(set = 0, binding = " + de::toString(numUsedBindings) + ", rgba8) readonly uniform highp image" + dimension + " u_image[2];\n";
6433				default:
6434					DE_FATAL("invalid descriptor");
6435					return "";
6436			}
6437
6438		default:
6439			DE_FATAL("Impossible");
6440			return "";
6441	}
6442}
6443
6444std::string ImageDescriptorCase::genFetchCoordStr (int fetchPosNdx) const
6445{
6446	DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
6447	const tcu::IVec3 fetchPos = ImageFetchInstanceImages::getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
6448
6449	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
6450	{
6451		return de::toString(fetchPos.x());
6452	}
6453	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
6454	{
6455		std::ostringstream buf;
6456		buf << "ivec2(" << fetchPos.x() << ", " << fetchPos.y() << ")";
6457		return buf.str();
6458	}
6459	else
6460	{
6461		std::ostringstream buf;
6462		buf << "ivec3(" << fetchPos.x() << ", " << fetchPos.y() << ", " << fetchPos.z() << ")";
6463		return buf.str();
6464	}
6465}
6466
6467std::string ImageDescriptorCase::genSampleCoordStr (int samplePosNdx) const
6468{
6469	DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
6470	const tcu::Vec4 fetchPos = ImageSampleInstanceImages::getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
6471
6472	if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
6473	{
6474		std::ostringstream buf;
6475		buf << "float(" << fetchPos.x() << ")";
6476		return buf.str();
6477	}
6478	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
6479	{
6480		std::ostringstream buf;
6481		buf << "vec2(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "))";
6482		return buf.str();
6483	}
6484	else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
6485	{
6486		std::ostringstream buf;
6487		buf << "vec4(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "), float(" << fetchPos.w() << "))";
6488		return buf.str();
6489	}
6490	else
6491	{
6492		std::ostringstream buf;
6493		buf << "vec3(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "))";
6494		return buf.str();
6495	}
6496}
6497
6498std::string ImageDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
6499{
6500	DE_UNREF(stage);
6501
6502	const char* const	dimension		= (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)			? ("1D")
6503										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)	? ("1DArray")
6504										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)			? ("2D")
6505										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)	? ("2DArray")
6506										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D)			? ("3D")
6507										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE)		? ("Cube")
6508										: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)	? ("CubeArray")
6509										: (DE_NULL);
6510	const char* const	accessPostfixA	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? ("")
6511										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? ("A")
6512										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS)	? ("A")
6513										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? ("[0]")
6514										: (DE_NULL);
6515	const char* const	accessPostfixB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? ("")
6516										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? ("B")
6517										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS)	? ("B")
6518										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? ("[1]")
6519										: (DE_NULL);
6520
6521	switch (m_descriptorType)
6522	{
6523		case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
6524		case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6525		{
6526			const std::string	coodStr[4]	=
6527			{
6528				genSampleCoordStr(0),
6529				genSampleCoordStr(1),
6530				genSampleCoordStr(2),
6531				genSampleCoordStr(3),
6532			};
6533			std::ostringstream	buf;
6534
6535			if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
6536			{
6537				buf << "	if (quadrant_id == 0)\n"
6538					<< "		result_color = textureLod(sampler" << dimension << "(u_separateTexture, u_separateSampler" << accessPostfixA << "), " << coodStr[0] << ", 0.0);\n"
6539					<< "	else if (quadrant_id == 1)\n"
6540					<< "		result_color = textureLod(sampler" << dimension << "(u_separateTexture, u_separateSampler" << accessPostfixB << "), " << coodStr[1] << ", 0.0);\n"
6541					<< "	else if (quadrant_id == 2)\n"
6542					<< "		result_color = textureLod(sampler" << dimension << "(u_separateTexture, u_separateSampler" << accessPostfixA << "), " << coodStr[2] << ", 0.0);\n"
6543					<< "	else\n"
6544					<< "		result_color = textureLod(sampler" << dimension << "(u_separateTexture, u_separateSampler" << accessPostfixB << "), " << coodStr[3] << ", 0.0);\n";
6545			}
6546			else
6547			{
6548				buf << "	if (quadrant_id == 0)\n"
6549					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixA << ", " << coodStr[0] << ", 0.0);\n"
6550					<< "	else if (quadrant_id == 1)\n"
6551					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixB << ", " << coodStr[1] << ", 0.0);\n"
6552					<< "	else if (quadrant_id == 2)\n"
6553					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixA << ", " << coodStr[2] << ", 0.0);\n"
6554					<< "	else\n"
6555					<< "		result_color = textureLod(u_combinedTextureSampler" << accessPostfixB << ", " << coodStr[3] << ", 0.0);\n";
6556			}
6557
6558			return buf.str();
6559		}
6560
6561		case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6562		{
6563			const std::string	coodStr[4]	=
6564			{
6565				genFetchCoordStr(0),
6566				genFetchCoordStr(1),
6567				genFetchCoordStr(2),
6568				genFetchCoordStr(3),
6569			};
6570			std::ostringstream	buf;
6571
6572			buf << "	if (quadrant_id == 0)\n"
6573				<< "		result_color = imageLoad(u_image" << accessPostfixA << ", " << coodStr[0] << ");\n"
6574				<< "	else if (quadrant_id == 1)\n"
6575				<< "		result_color = imageLoad(u_image" << accessPostfixB << ", " << coodStr[1] << ");\n"
6576				<< "	else if (quadrant_id == 2)\n"
6577				<< "		result_color = imageLoad(u_image" << accessPostfixA << ", " << coodStr[2] << ");\n"
6578				<< "	else\n"
6579				<< "		result_color = imageLoad(u_image" << accessPostfixB << ", " << coodStr[3] << ");\n";
6580
6581			return buf.str();
6582		}
6583
6584		default:
6585			DE_FATAL("invalid descriptor");
6586			return "";
6587	}
6588}
6589
6590std::string ImageDescriptorCase::genNoAccessSource (void) const
6591{
6592	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
6593			"		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
6594			"	else\n"
6595			"		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
6596}
6597
6598vkt::TestInstance* ImageDescriptorCase::createInstance (vkt::Context& context) const
6599{
6600	verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages);
6601
6602	switch (m_descriptorType)
6603	{
6604		case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
6605		case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
6606			if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
6607			{
6608				DE_ASSERT(m_isPrimaryCmdBuf);
6609				return new ImageSampleComputeInstance(context, m_updateMethod, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
6610			}
6611			else
6612				return new ImageSampleRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
6613
6614		case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
6615		case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
6616			if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
6617			{
6618				DE_ASSERT(m_isPrimaryCmdBuf);
6619				return new ImageFetchComputeInstance(context, m_updateMethod, m_descriptorType, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
6620			}
6621			else
6622				return new ImageFetchRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
6623
6624		default:
6625			DE_FATAL("Impossible");
6626			return DE_NULL;
6627	}
6628}
6629
6630class TexelBufferInstanceBuffers
6631{
6632public:
6633											TexelBufferInstanceBuffers	(const vk::DeviceInterface&		vki,
6634																		 vk::VkDevice					device,
6635																		 vk::Allocator&					allocator,
6636																		 vk::VkDescriptorType			descriptorType,
6637																		 int							numTexelBuffers,
6638																		 bool							hasViewOffset);
6639
6640private:
6641	static vk::Move<vk::VkBuffer>			createBuffer				(const vk::DeviceInterface&		vki,
6642																		 vk::VkDevice					device,
6643																		 vk::Allocator&					allocator,
6644																		 vk::VkDescriptorType			descriptorType,
6645																		 de::MovePtr<vk::Allocation>	*outAllocation);
6646
6647	static vk::Move<vk::VkBufferView>		createBufferView			(const vk::DeviceInterface&		vki,
6648																		 vk::VkDevice					device,
6649																		 const tcu::TextureFormat&		textureFormat,
6650																		 deUint32						offset,
6651																		 vk::VkBuffer					buffer);
6652
6653	static vk::VkBufferMemoryBarrier		createBarrier				(vk::VkDescriptorType descriptorType, vk::VkBuffer buffer);
6654
6655	void									populateSourceBuffer		(const tcu::PixelBufferAccess& access);
6656	void									uploadData					(const vk::DeviceInterface& vki, vk::VkDevice device, const vk::Allocation& memory, const de::ArrayBuffer<deUint8>& data);
6657
6658public:
6659	static int								getFetchPos					(int fetchPosNdx);
6660	tcu::Vec4								fetchTexelValue				(int fetchPosNdx) const;
6661
6662	inline int								getNumTexelBuffers			(void) const { return m_numTexelBuffers;	}
6663	const tcu::TextureFormat&				getTextureFormat			(void) const { return m_imageFormat;		}
6664	inline vk::VkBufferView					getBufferViewA				(void) const { return *m_bufferViewA;		}
6665	inline vk::VkBufferView					getBufferViewB				(void) const { return *m_bufferViewB;		}
6666	inline const vk::VkBufferMemoryBarrier*	getBufferInitBarriers		(void) const { return m_bufferBarriers;		}
6667
6668private:
6669	enum
6670	{
6671		BUFFER_SIZE			= 512,
6672		VIEW_OFFSET_VALUE	= 256,
6673		VIEW_DATA_SIZE		= 256,	//!< size in bytes
6674		VIEW_WIDTH			= 64,	//!< size in pixels
6675	};
6676	enum
6677	{
6678		// some arbitrary points
6679		SAMPLE_POINT_0 = 6,
6680		SAMPLE_POINT_1 = 51,
6681		SAMPLE_POINT_2 = 42,
6682		SAMPLE_POINT_3 = 25,
6683	};
6684
6685	const deUint32							m_numTexelBuffers;
6686	const tcu::TextureFormat				m_imageFormat;
6687	const deUint32							m_viewOffset;
6688
6689	de::ArrayBuffer<deUint8>				m_sourceBufferA;
6690	de::ArrayBuffer<deUint8>				m_sourceBufferB;
6691	const tcu::ConstPixelBufferAccess		m_sourceViewA;
6692	const tcu::ConstPixelBufferAccess		m_sourceViewB;
6693
6694	de::MovePtr<vk::Allocation>				m_bufferMemoryA;
6695	de::MovePtr<vk::Allocation>				m_bufferMemoryB;
6696	const vk::Unique<vk::VkBuffer>			m_bufferA;
6697	const vk::Unique<vk::VkBuffer>			m_bufferB;
6698	const vk::Unique<vk::VkBufferView>		m_bufferViewA;
6699	const vk::Unique<vk::VkBufferView>		m_bufferViewB;
6700	vk::VkBufferMemoryBarrier				m_bufferBarriers[2];
6701};
6702
6703TexelBufferInstanceBuffers::TexelBufferInstanceBuffers (const vk::DeviceInterface&		vki,
6704														vk::VkDevice					device,
6705														vk::Allocator&					allocator,
6706														vk::VkDescriptorType			descriptorType,
6707														int								numTexelBuffers,
6708														bool							hasViewOffset)
6709	: m_numTexelBuffers	(numTexelBuffers)
6710	, m_imageFormat		(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
6711	, m_viewOffset		((hasViewOffset) ? ((deUint32)VIEW_OFFSET_VALUE) : (0u))
6712	, m_sourceBufferA	(BUFFER_SIZE)
6713	, m_sourceBufferB	((numTexelBuffers == 1)
6714							? (0u)
6715							: ((size_t)BUFFER_SIZE))
6716	, m_sourceViewA		(m_imageFormat, tcu::IVec3(VIEW_WIDTH, 1, 1), m_sourceBufferA.getElementPtr(m_viewOffset))
6717	, m_sourceViewB		(m_imageFormat, tcu::IVec3(VIEW_WIDTH, 1, 1), m_sourceBufferB.getElementPtr(m_viewOffset))
6718	, m_bufferMemoryA	(DE_NULL)
6719	, m_bufferMemoryB	(DE_NULL)
6720	, m_bufferA			(createBuffer(vki, device, allocator, descriptorType, &m_bufferMemoryA))
6721	, m_bufferB			((numTexelBuffers == 1)
6722							? vk::Move<vk::VkBuffer>()
6723							: createBuffer(vki, device, allocator, descriptorType, &m_bufferMemoryB))
6724	, m_bufferViewA		(createBufferView(vki, device, m_imageFormat, m_viewOffset, *m_bufferA))
6725	, m_bufferViewB		((numTexelBuffers == 1)
6726							? vk::Move<vk::VkBufferView>()
6727							: createBufferView(vki, device, m_imageFormat, m_viewOffset, *m_bufferB))
6728{
6729	DE_ASSERT(numTexelBuffers == 1 || numTexelBuffers == 2);
6730	DE_ASSERT(VIEW_WIDTH * m_imageFormat.getPixelSize() == VIEW_DATA_SIZE);
6731	DE_ASSERT(BUFFER_SIZE % m_imageFormat.getPixelSize() == 0);
6732
6733	// specify and upload
6734
6735	populateSourceBuffer(tcu::PixelBufferAccess(m_imageFormat, tcu::IVec3(BUFFER_SIZE / m_imageFormat.getPixelSize(), 1, 1), m_sourceBufferA.getPtr()));
6736	uploadData(vki, device, *m_bufferMemoryA, m_sourceBufferA);
6737
6738	if (numTexelBuffers == 2)
6739	{
6740		populateSourceBuffer(tcu::PixelBufferAccess(m_imageFormat, tcu::IVec3(BUFFER_SIZE / m_imageFormat.getPixelSize(), 1, 1), m_sourceBufferB.getPtr()));
6741		uploadData(vki, device, *m_bufferMemoryB, m_sourceBufferB);
6742	}
6743
6744	m_bufferBarriers[0] = createBarrier(descriptorType, *m_bufferA);
6745	m_bufferBarriers[1] = createBarrier(descriptorType, *m_bufferB);
6746}
6747
6748vk::Move<vk::VkBuffer> TexelBufferInstanceBuffers::createBuffer (const vk::DeviceInterface&		vki,
6749																 vk::VkDevice					device,
6750																 vk::Allocator&					allocator,
6751																 vk::VkDescriptorType			descriptorType,
6752																 de::MovePtr<vk::Allocation>	*outAllocation)
6753{
6754	const vk::VkBufferUsageFlags	usage		= (isUniformDescriptorType(descriptorType)) ? (vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
6755	const vk::VkBufferCreateInfo	createInfo	=
6756	{
6757		vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
6758		DE_NULL,
6759		0u,									// flags
6760		(vk::VkDeviceSize)BUFFER_SIZE,		// size
6761		usage,								// usage
6762		vk::VK_SHARING_MODE_EXCLUSIVE,		// sharingMode
6763		0u,									// queueFamilyCount
6764		DE_NULL,							// pQueueFamilyIndices
6765	};
6766	vk::Move<vk::VkBuffer>			buffer		(vk::createBuffer(vki, device, &createInfo));
6767	de::MovePtr<vk::Allocation>		allocation	(allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
6768
6769	*outAllocation = allocation;
6770	return buffer;
6771}
6772
6773vk::Move<vk::VkBufferView> TexelBufferInstanceBuffers::createBufferView (const vk::DeviceInterface&		vki,
6774																		 vk::VkDevice					device,
6775																		 const tcu::TextureFormat&		textureFormat,
6776																		 deUint32						offset,
6777																		 vk::VkBuffer					buffer)
6778{
6779	const vk::VkBufferViewCreateInfo createInfo =
6780	{
6781		vk::VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
6782		DE_NULL,
6783		(vk::VkBufferViewCreateFlags)0,
6784		buffer,									// buffer
6785		vk::mapTextureFormat(textureFormat),	// format
6786		(vk::VkDeviceSize)offset,				// offset
6787		(vk::VkDeviceSize)VIEW_DATA_SIZE		// range
6788	};
6789	return vk::createBufferView(vki, device, &createInfo);
6790}
6791
6792vk::VkBufferMemoryBarrier TexelBufferInstanceBuffers::createBarrier (vk::VkDescriptorType descriptorType, vk::VkBuffer buffer)
6793{
6794	const vk::VkAccessFlags			inputBit	= (isUniformDescriptorType(descriptorType)) ? (vk::VK_ACCESS_UNIFORM_READ_BIT) : (vk::VK_ACCESS_SHADER_READ_BIT);
6795	const vk::VkBufferMemoryBarrier	barrier		=
6796	{
6797		vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
6798		DE_NULL,
6799		vk::VK_ACCESS_HOST_WRITE_BIT,			// outputMask
6800		inputBit,								// inputMask
6801		VK_QUEUE_FAMILY_IGNORED,				// srcQueueFamilyIndex
6802		VK_QUEUE_FAMILY_IGNORED,				// destQueueFamilyIndex
6803		buffer	,								// buffer
6804		0u,										// offset
6805		(vk::VkDeviceSize)BUFFER_SIZE			// size
6806	};
6807	return barrier;
6808}
6809
6810void TexelBufferInstanceBuffers::populateSourceBuffer (const tcu::PixelBufferAccess& access)
6811{
6812	DE_ASSERT(access.getHeight() == 1);
6813	DE_ASSERT(access.getDepth() == 1);
6814
6815	const deInt32 width = access.getWidth();
6816
6817	for (int x = 0; x < width; ++x)
6818	{
6819		const int			red		= 255 * x / width;												//!< gradient from 0 -> max (detects large offset errors)
6820		const int			green	= ((x % 2 == 0) ? (127) : (0)) + ((x % 4 < 3) ? (128) : (0));	//!< 3-level M pattern (detects small offset errors)
6821		const int			blue	= 16 * (x % 16);												//!< 16-long triangle wave
6822
6823		DE_ASSERT(de::inRange(red, 0, 255));
6824		DE_ASSERT(de::inRange(green, 0, 255));
6825		DE_ASSERT(de::inRange(blue, 0, 255));
6826
6827		access.setPixel(tcu::IVec4(red, green, blue, 255), x, 0, 0);
6828	}
6829}
6830
6831void TexelBufferInstanceBuffers::uploadData (const vk::DeviceInterface& vki, vk::VkDevice device, const vk::Allocation& memory, const de::ArrayBuffer<deUint8>& data)
6832{
6833	deMemcpy(memory.getHostPtr(), data.getPtr(), data.size());
6834	flushMappedMemoryRange(vki, device, memory.getMemory(), memory.getOffset(), data.size());
6835}
6836
6837int TexelBufferInstanceBuffers::getFetchPos (int fetchPosNdx)
6838{
6839	static const int fetchPositions[4] =
6840	{
6841		SAMPLE_POINT_0,
6842		SAMPLE_POINT_1,
6843		SAMPLE_POINT_2,
6844		SAMPLE_POINT_3,
6845	};
6846	return de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
6847}
6848
6849tcu::Vec4 TexelBufferInstanceBuffers::fetchTexelValue (int fetchPosNdx) const
6850{
6851	// source order is ABAB
6852	const tcu::ConstPixelBufferAccess&	texelSrcA	= m_sourceViewA;
6853	const tcu::ConstPixelBufferAccess&	texelSrcB	= (m_numTexelBuffers == 1) ? (m_sourceViewA) : (m_sourceViewB);
6854	const tcu::ConstPixelBufferAccess&	texelSrc	= ((fetchPosNdx % 2) == 0) ? (texelSrcA) : (texelSrcB);
6855
6856	return texelSrc.getPixel(getFetchPos(fetchPosNdx), 0, 0);
6857}
6858
6859class TexelBufferRenderInstance : public SingleCmdRenderInstance
6860{
6861public:
6862													TexelBufferRenderInstance		(vkt::Context&									context,
6863																					 DescriptorUpdateMethod							updateMethod,
6864																					 bool											isPrimaryCmdBuf,
6865																					 vk::VkDescriptorType							descriptorType,
6866																					 vk::VkShaderStageFlags							stageFlags,
6867																					 ShaderInputInterface							shaderInterface,
6868																					 bool											nonzeroViewOffset);
6869
6870private:
6871	static vk::Move<vk::VkDescriptorSetLayout>		createDescriptorSetLayout		(const vk::DeviceInterface&						vki,
6872																					 vk::VkDevice									device,
6873																					 vk::VkDescriptorType							descriptorType,
6874																					 ShaderInputInterface							shaderInterface,
6875																					 vk::VkShaderStageFlags							stageFlags,
6876																					 DescriptorUpdateMethod							updateMethod);
6877
6878	static vk::Move<vk::VkPipelineLayout>			createPipelineLayout			(const vk::DeviceInterface&						vki,
6879																					 vk::VkDevice									device,
6880																					 vk::VkDescriptorSetLayout						descriptorSetLayout);
6881
6882	static vk::Move<vk::VkDescriptorPool>			createDescriptorPool			(const vk::DeviceInterface&						vki,
6883																					 vk::VkDevice									device,
6884																					 vk::VkDescriptorType							descriptorType,
6885																					 ShaderInputInterface							shaderInterface);
6886
6887	static vk::Move<vk::VkDescriptorSet>			createDescriptorSet				(const vk::DeviceInterface&						vki,
6888																					 DescriptorUpdateMethod							updateMethod,
6889																					 vk::VkDevice									device,
6890																					 vk::VkDescriptorType							descriptorType,
6891																					 ShaderInputInterface							shaderInterface,
6892																					 vk::VkDescriptorSetLayout						layout,
6893																					 vk::VkDescriptorPool							pool,
6894																					 vk::VkBufferView								viewA,
6895																					 vk::VkBufferView								viewB,
6896																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
6897																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
6898																					 RawUpdateRegistry&								updateRegistry,
6899																					 vk::VkPipelineLayout							pipelineLayout = DE_NULL);
6900
6901	static void										writeDescriptorSet				(const vk::DeviceInterface&						vki,
6902																					 vk::VkDevice									device,
6903																					 vk::VkDescriptorType							descriptorType,
6904																					 ShaderInputInterface							shaderInterface,
6905																					 vk::VkDescriptorSetLayout						layout,
6906																					 vk::VkDescriptorPool							pool,
6907																					 vk::VkBufferView								viewA,
6908																					 vk::VkBufferView								viewB,
6909																					 vk::VkDescriptorSet							descriptorSet,
6910																					 vk::DescriptorSetUpdateBuilder&				updateBuilder,
6911																					 DescriptorUpdateMethod							updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
6912
6913	static void										writeDescriptorSetWithTemplate	(const vk::DeviceInterface&						vki,
6914																					 vk::VkDevice									device,
6915																					 vk::VkDescriptorType							descriptorType,
6916																					 ShaderInputInterface							shaderInterface,
6917																					 vk::VkDescriptorSetLayout						layout,
6918																					 vk::VkDescriptorPool							pool,
6919																					 vk::VkBufferView								viewA,
6920																					 vk::VkBufferView								viewB,
6921																					 vk::VkDescriptorSet							descriptorSet,
6922																					 vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
6923																					 RawUpdateRegistry&								updateRegistry,
6924																					 bool											withPush = false,
6925																					 vk::VkPipelineLayout							pipelineLayout = 0);
6926
6927	void											logTestPlan						(void) const;
6928	vk::VkPipelineLayout							getPipelineLayout				(void) const;
6929	void											writeDrawCmdBuffer				(vk::VkCommandBuffer cmd) const;
6930	tcu::TestStatus									verifyResultImage				(const tcu::ConstPixelBufferAccess& result) const;
6931
6932	enum
6933	{
6934		RENDER_SIZE = 128,
6935	};
6936
6937	const DescriptorUpdateMethod					m_updateMethod;
6938	const vk::VkDescriptorType						m_descriptorType;
6939	const vk::VkShaderStageFlags					m_stageFlags;
6940	const ShaderInputInterface						m_shaderInterface;
6941	const bool										m_nonzeroViewOffset;
6942
6943	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
6944	RawUpdateRegistry								m_updateRegistry;
6945	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
6946	const vk::Unique<vk::VkDescriptorSetLayout>		m_descriptorSetLayout;
6947	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
6948	const TexelBufferInstanceBuffers				m_texelBuffers;
6949	const vk::Unique<vk::VkDescriptorPool>			m_descriptorPool;
6950	const vk::Unique<vk::VkDescriptorSet>			m_descriptorSet;
6951};
6952
6953TexelBufferRenderInstance::TexelBufferRenderInstance (vkt::Context&					context,
6954													  DescriptorUpdateMethod		updateMethod,
6955													  bool							isPrimaryCmdBuf,
6956													  vk::VkDescriptorType			descriptorType,
6957													  vk::VkShaderStageFlags		stageFlags,
6958													  ShaderInputInterface			shaderInterface,
6959													  bool							nonzeroViewOffset)
6960	: SingleCmdRenderInstance	(context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
6961	, m_updateMethod			(updateMethod)
6962	, m_descriptorType			(descriptorType)
6963	, m_stageFlags				(stageFlags)
6964	, m_shaderInterface			(shaderInterface)
6965	, m_nonzeroViewOffset		(nonzeroViewOffset)
6966	, m_updateTemplate			()
6967	, m_updateRegistry			()
6968	, m_updateBuilder			()
6969	, m_descriptorSetLayout		(createDescriptorSetLayout(m_vki, m_device, m_descriptorType, m_shaderInterface, m_stageFlags, m_updateMethod))
6970	, m_pipelineLayout			(createPipelineLayout(m_vki, m_device, *m_descriptorSetLayout))
6971	, m_texelBuffers			(m_vki, m_device, m_allocator, m_descriptorType, getInterfaceNumResources(m_shaderInterface), m_nonzeroViewOffset)
6972	, m_descriptorPool			(createDescriptorPool(m_vki, m_device, m_descriptorType, m_shaderInterface))
6973	, m_descriptorSet			(createDescriptorSet(m_vki, m_updateMethod, m_device, m_descriptorType, m_shaderInterface, *m_descriptorSetLayout, *m_descriptorPool, m_texelBuffers.getBufferViewA(), m_texelBuffers.getBufferViewB(), m_updateBuilder, m_updateTemplate, m_updateRegistry, *m_pipelineLayout))
6974{
6975}
6976
6977vk::Move<vk::VkDescriptorSetLayout> TexelBufferRenderInstance::createDescriptorSetLayout (const vk::DeviceInterface&	vki,
6978																						  vk::VkDevice					device,
6979																						  vk::VkDescriptorType			descriptorType,
6980																						  ShaderInputInterface			shaderInterface,
6981																						  vk::VkShaderStageFlags		stageFlags,
6982																						  DescriptorUpdateMethod		updateMethod)
6983{
6984	vk::DescriptorSetLayoutBuilder builder;
6985	vk::VkDescriptorSetLayoutCreateFlags	extraFlags			= 0;
6986
6987	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
6988			updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
6989	{
6990		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
6991	}
6992
6993	switch (shaderInterface)
6994	{
6995		case SHADER_INPUT_SINGLE_DESCRIPTOR:
6996			builder.addSingleBinding(descriptorType, stageFlags);
6997			break;
6998
6999		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7000			builder.addSingleBinding(descriptorType, stageFlags);
7001			builder.addSingleBinding(descriptorType, stageFlags);
7002			break;
7003
7004		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7005			builder.addArrayBinding(descriptorType, 2u, stageFlags);
7006			break;
7007
7008		default:
7009			DE_FATAL("Impossible");
7010	}
7011
7012	return builder.build(vki, device, extraFlags);
7013}
7014
7015vk::Move<vk::VkPipelineLayout> TexelBufferRenderInstance::createPipelineLayout (const vk::DeviceInterface&	vki,
7016																				vk::VkDevice				device,
7017																				vk::VkDescriptorSetLayout	descriptorSetLayout)
7018{
7019	const vk::VkPipelineLayoutCreateInfo createInfo =
7020	{
7021		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
7022		DE_NULL,
7023		(vk::VkPipelineLayoutCreateFlags)0,
7024		1,						// descriptorSetCount
7025		&descriptorSetLayout,	// pSetLayouts
7026		0u,						// pushConstantRangeCount
7027		DE_NULL,				// pPushConstantRanges
7028	};
7029	return vk::createPipelineLayout(vki, device, &createInfo);
7030}
7031
7032vk::Move<vk::VkDescriptorPool> TexelBufferRenderInstance::createDescriptorPool (const vk::DeviceInterface&	vki,
7033																				vk::VkDevice					device,
7034																				vk::VkDescriptorType			descriptorType,
7035																				ShaderInputInterface			shaderInterface)
7036{
7037	return vk::DescriptorPoolBuilder()
7038		.addType(descriptorType, getInterfaceNumResources(shaderInterface))
7039		.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
7040}
7041
7042vk::Move<vk::VkDescriptorSet> TexelBufferRenderInstance::createDescriptorSet (const vk::DeviceInterface&					vki,
7043																			  DescriptorUpdateMethod						updateMethod,
7044																			  vk::VkDevice									device,
7045																			  vk::VkDescriptorType							descriptorType,
7046																			  ShaderInputInterface							shaderInterface,
7047																			  vk::VkDescriptorSetLayout						layout,
7048																			  vk::VkDescriptorPool							pool,
7049																			  vk::VkBufferView								viewA,
7050																			  vk::VkBufferView								viewB,
7051																			  vk::DescriptorSetUpdateBuilder&				updateBuilder,
7052																			  vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
7053																			  RawUpdateRegistry&							updateRegistry,
7054																			  vk::VkPipelineLayout							pipelineLayout)
7055{
7056	const vk::VkDescriptorSetAllocateInfo	allocInfo			=
7057	{
7058		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
7059		DE_NULL,
7060		pool,
7061		1u,
7062		&layout
7063	};
7064
7065	vk::Move<vk::VkDescriptorSet>			descriptorSet;
7066	if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7067	{
7068		descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
7069	}
7070	else
7071	{
7072		descriptorSet = vk::Move<vk::VkDescriptorSet>();
7073	}
7074
7075	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
7076	{
7077		writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplate, updateRegistry);
7078	}
7079	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7080	{
7081		writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplate, updateRegistry, true, pipelineLayout);
7082	}
7083	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
7084	{
7085		writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, updateMethod);
7086	}
7087	else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
7088	{
7089		writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder);
7090	}
7091
7092	return descriptorSet;
7093}
7094
7095void TexelBufferRenderInstance::writeDescriptorSet (const vk::DeviceInterface&						vki,
7096													vk::VkDevice									device,
7097													vk::VkDescriptorType							descriptorType,
7098													ShaderInputInterface							shaderInterface,
7099													vk::VkDescriptorSetLayout						layout,
7100													vk::VkDescriptorPool							pool,
7101													vk::VkBufferView								viewA,
7102													vk::VkBufferView								viewB,
7103												    vk::VkDescriptorSet								descriptorSet,
7104												    vk::DescriptorSetUpdateBuilder&					updateBuilder,
7105												    DescriptorUpdateMethod							updateMethod)
7106{
7107	DE_UNREF(layout);
7108	DE_UNREF(pool);
7109	const vk::VkBufferView					texelBufferInfos[2]	=
7110	{
7111		viewA,
7112		viewB,
7113	};
7114
7115	switch (shaderInterface)
7116	{
7117		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7118			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
7119			break;
7120
7121		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7122			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
7123			updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &texelBufferInfos[1]);
7124			break;
7125
7126		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7127			updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, texelBufferInfos);
7128			break;
7129
7130		default:
7131			DE_FATAL("Impossible");
7132	}
7133
7134	if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
7135	{
7136		updateBuilder.update(vki, device);
7137	}
7138}
7139
7140void TexelBufferRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface&						vki,
7141																vk::VkDevice									device,
7142																vk::VkDescriptorType							descriptorType,
7143																ShaderInputInterface							shaderInterface,
7144																vk::VkDescriptorSetLayout						layout,
7145																vk::VkDescriptorPool							pool,
7146																vk::VkBufferView								viewA,
7147																vk::VkBufferView								viewB,
7148																vk::VkDescriptorSet								descriptorSet,
7149																vk::Move<vk::VkDescriptorUpdateTemplate>&		updateTemplate,
7150																RawUpdateRegistry&								updateRegistry,
7151																bool											withPush,
7152																vk::VkPipelineLayout							pipelineLayout)
7153{
7154	DE_UNREF(pool);
7155	const vk::VkBufferView									texelBufferInfos[2]	=
7156	{
7157		viewA,
7158		viewB,
7159	};
7160	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
7161	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
7162	{
7163		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
7164		DE_NULL,
7165		0,
7166		0,			// updateCount
7167		DE_NULL,	// pUpdates
7168		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
7169		layout,
7170		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
7171		pipelineLayout,
7172		0
7173	};
7174	updateRegistry.addWriteObject(texelBufferInfos[0]);
7175	updateRegistry.addWriteObject(texelBufferInfos[1]);
7176
7177	switch (shaderInterface)
7178	{
7179		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7180			updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
7181			break;
7182
7183		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7184			updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
7185			updateEntries.push_back(createTemplateBinding(1, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
7186			break;
7187
7188		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7189			updateEntries.push_back(createTemplateBinding(0, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(texelBufferInfos[0])));
7190			break;
7191
7192		default:
7193			DE_FATAL("Impossible");
7194	}
7195
7196	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
7197	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
7198
7199	updateTemplate									= vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
7200
7201	if (!withPush)
7202	{
7203		vki.updateDescriptorSetWithTemplate(device, descriptorSet, *updateTemplate, updateRegistry.getRawPointer());
7204	}
7205}
7206
7207void TexelBufferRenderInstance::logTestPlan (void) const
7208{
7209	std::ostringstream msg;
7210
7211	msg << "Rendering 2x2 grid.\n"
7212		<< "Single descriptor set. Descriptor set contains "
7213			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
7214			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
7215			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
7216			    (const char*)DE_NULL)
7217		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
7218		<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
7219		<< "Buffer format is " << vk::getFormatName(vk::mapTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
7220
7221	if (m_stageFlags == 0u)
7222	{
7223		msg << "Descriptors are not accessed in any shader stage.\n";
7224	}
7225	else
7226	{
7227		msg << "Color in each cell is fetched using the descriptor(s):\n";
7228
7229		for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
7230		{
7231			msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
7232
7233			if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
7234			{
7235				const int srcResourceNdx = (resultNdx % 2); // ABAB source
7236				msg << " from texelBuffer " << srcResourceNdx;
7237			}
7238
7239			msg << "\n";
7240		}
7241
7242		msg << "Descriptors are accessed in {"
7243			<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0)					? (" vertex")			: (""))
7244			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0)	? (" tess_control")		: (""))
7245			<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0)	? (" tess_evaluation")	: (""))
7246			<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0)				? (" geometry")			: (""))
7247			<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0)				? (" fragment")			: (""))
7248			<< " } stages.";
7249	}
7250
7251	m_context.getTestContext().getLog()
7252		<< tcu::TestLog::Message
7253		<< msg.str()
7254		<< tcu::TestLog::EndMessage;
7255}
7256
7257vk::VkPipelineLayout TexelBufferRenderInstance::getPipelineLayout (void) const
7258{
7259	return *m_pipelineLayout;
7260}
7261
7262void TexelBufferRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
7263{
7264	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
7265	{
7266		m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, 1, &m_descriptorSet.get(), 0, DE_NULL);
7267	}
7268	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7269	{
7270		m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, *m_updateTemplate, getPipelineLayout(), 0, (const void*)m_updateRegistry.getRawPointer());
7271	}
7272	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
7273	{
7274		m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0);
7275	}
7276
7277	m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
7278}
7279
7280tcu::TestStatus TexelBufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
7281{
7282	const tcu::Vec4		green		(0.0f, 1.0f, 0.0f, 1.0f);
7283	const tcu::Vec4		yellow		(1.0f, 1.0f, 0.0f, 1.0f);
7284	const bool			doFetch		= (m_stageFlags != 0u); // no active stages? Then don't fetch
7285	const tcu::Vec4		sample0		= (!doFetch) ? (yellow)	: (m_texelBuffers.fetchTexelValue(0));
7286	const tcu::Vec4		sample1		= (!doFetch) ? (green)	: (m_texelBuffers.fetchTexelValue(1));
7287	const tcu::Vec4		sample2		= (!doFetch) ? (green)	: (m_texelBuffers.fetchTexelValue(2));
7288	const tcu::Vec4		sample3		= (!doFetch) ? (yellow)	: (m_texelBuffers.fetchTexelValue(3));
7289	tcu::Surface		reference	(m_targetSize.x(), m_targetSize.y());
7290
7291	drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
7292
7293	if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
7294		return tcu::TestStatus::fail("Image verification failed");
7295	else
7296		return tcu::TestStatus::pass("Pass");
7297}
7298
7299class TexelBufferComputeInstance : public vkt::TestInstance
7300{
7301public:
7302													TexelBufferComputeInstance			(vkt::Context&					context,
7303																						 DescriptorUpdateMethod			updateMethod,
7304																						 vk::VkDescriptorType			descriptorType,
7305																						 ShaderInputInterface			shaderInterface,
7306																						 bool							nonzeroViewOffset);
7307
7308private:
7309	vk::Move<vk::VkDescriptorSetLayout>				createDescriptorSetLayout			(void) const;
7310	vk::Move<vk::VkDescriptorPool>					createDescriptorPool				(void) const;
7311	vk::Move<vk::VkDescriptorSet>					createDescriptorSet					(vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout);
7312	void											writeDescriptorSet					(vk::VkDescriptorSet descriptorSet);
7313	void											writeDescriptorSetWithTemplate		(vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
7314
7315	tcu::TestStatus									iterate								(void);
7316	void											logTestPlan							(void) const;
7317	tcu::TestStatus									testResourceAccess					(void);
7318
7319	const DescriptorUpdateMethod					m_updateMethod;
7320	const vk::VkDescriptorType						m_descriptorType;
7321	const ShaderInputInterface						m_shaderInterface;
7322	const bool										m_nonzeroViewOffset;
7323
7324	const vk::DeviceInterface&						m_vki;
7325	const vk::VkDevice								m_device;
7326	const vk::VkQueue								m_queue;
7327	const deUint32									m_queueFamilyIndex;
7328	vk::Allocator&									m_allocator;
7329	vk::Move<vk::VkDescriptorUpdateTemplate>		m_updateTemplate;
7330
7331	const ComputeInstanceResultBuffer				m_result;
7332	const TexelBufferInstanceBuffers				m_texelBuffers;
7333
7334	RawUpdateRegistry								m_updateRegistry;
7335	vk::DescriptorSetUpdateBuilder					m_updateBuilder;
7336};
7337
7338TexelBufferComputeInstance::TexelBufferComputeInstance (Context&					context,
7339														DescriptorUpdateMethod		updateMethod,
7340														vk::VkDescriptorType		descriptorType,
7341														ShaderInputInterface		shaderInterface,
7342														bool						nonzeroViewOffset)
7343	: vkt::TestInstance		(context)
7344	, m_updateMethod		(updateMethod)
7345	, m_descriptorType		(descriptorType)
7346	, m_shaderInterface		(shaderInterface)
7347	, m_nonzeroViewOffset	(nonzeroViewOffset)
7348	, m_vki					(context.getDeviceInterface())
7349	, m_device				(context.getDevice())
7350	, m_queue				(context.getUniversalQueue())
7351	, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
7352	, m_allocator			(context.getDefaultAllocator())
7353	, m_updateTemplate		()
7354	, m_result				(m_vki, m_device, m_allocator)
7355	, m_texelBuffers		(m_vki, m_device, m_allocator, m_descriptorType, getInterfaceNumResources(m_shaderInterface), m_nonzeroViewOffset)
7356	, m_updateRegistry		()
7357	, m_updateBuilder		()
7358{
7359}
7360
7361vk::Move<vk::VkDescriptorSetLayout> TexelBufferComputeInstance::createDescriptorSetLayout (void) const
7362{
7363	vk::DescriptorSetLayoutBuilder builder;
7364	vk::VkDescriptorSetLayoutCreateFlags	extraFlags = 0;
7365
7366	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
7367			m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
7368	{
7369		extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
7370	}
7371
7372	builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT);
7373
7374	switch (m_shaderInterface)
7375	{
7376		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7377			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
7378			break;
7379
7380		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7381			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
7382			builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
7383			break;
7384
7385		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7386			builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
7387			break;
7388
7389		default:
7390			DE_FATAL("Impossible");
7391	};
7392
7393	return builder.build(m_vki, m_device, extraFlags);
7394}
7395
7396vk::Move<vk::VkDescriptorPool> TexelBufferComputeInstance::createDescriptorPool (void) const
7397{
7398	return vk::DescriptorPoolBuilder()
7399		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
7400		.addType(m_descriptorType, getInterfaceNumResources(m_shaderInterface))
7401		.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
7402}
7403
7404vk::Move<vk::VkDescriptorSet> TexelBufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout)
7405{
7406	const vk::VkDescriptorSetAllocateInfo	allocInfo			=
7407	{
7408		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
7409		DE_NULL,
7410		pool,
7411		1u,
7412		&layout
7413	};
7414
7415	vk::Move<vk::VkDescriptorSet>			descriptorSet;
7416	if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7417	{
7418		descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
7419	}
7420	else
7421	{
7422		descriptorSet = vk::Move<vk::VkDescriptorSet>();
7423	}
7424
7425
7426	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
7427	{
7428		writeDescriptorSetWithTemplate(*descriptorSet, layout);
7429	}
7430	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
7431	{
7432		writeDescriptorSet(*descriptorSet);
7433	}
7434
7435	return descriptorSet;
7436}
7437
7438void TexelBufferComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet)
7439{
7440	const vk::VkDescriptorBufferInfo		resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
7441	const vk::VkBufferView					texelBufferInfos[2]	=
7442	{
7443		m_texelBuffers.getBufferViewA(),
7444		m_texelBuffers.getBufferViewB(),
7445	};
7446
7447	// result
7448	m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
7449
7450	// texel buffers
7451	switch (m_shaderInterface)
7452	{
7453		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7454			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &texelBufferInfos[0]);
7455			break;
7456
7457		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7458			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, &texelBufferInfos[0]);
7459			m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), m_descriptorType, &texelBufferInfos[1]);
7460			break;
7461
7462		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7463			m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), m_descriptorType, 2u, texelBufferInfos);
7464			break;
7465
7466		default:
7467			DE_FATAL("Impossible");
7468	}
7469
7470	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
7471	{
7472		m_updateBuilder.update(m_vki, m_device);
7473	}
7474}
7475
7476void TexelBufferComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, bool withPush, vk::VkPipelineLayout pipelineLayout)
7477{
7478	const vk::VkDescriptorBufferInfo						resultInfo			= vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
7479	const vk::VkBufferView									texelBufferInfos[2]	=
7480	{
7481		m_texelBuffers.getBufferViewA(),
7482		m_texelBuffers.getBufferViewB(),
7483	};
7484	std::vector<vk::VkDescriptorUpdateTemplateEntry>		updateEntries;
7485	vk::VkDescriptorUpdateTemplateCreateInfo				templateCreateInfo	=
7486	{
7487		vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
7488		DE_NULL,
7489		0,
7490		0,			// updateCount
7491		DE_NULL,	// pUpdates
7492		withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
7493		layout,
7494		vk::VK_PIPELINE_BIND_POINT_COMPUTE,
7495		pipelineLayout,
7496		0
7497	};
7498	m_updateRegistry.addWriteObject(resultInfo);
7499	m_updateRegistry.addWriteObject(texelBufferInfos[0]);
7500	m_updateRegistry.addWriteObject(texelBufferInfos[1]);
7501
7502	// result
7503	updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_updateRegistry.getWriteObjectOffset(0), 0));
7504
7505	// texel buffers
7506	switch (m_shaderInterface)
7507	{
7508		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7509			updateEntries.push_back(createTemplateBinding(1, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
7510			break;
7511
7512		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7513			updateEntries.push_back(createTemplateBinding(1, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), 0));
7514			updateEntries.push_back(createTemplateBinding(2, 0, 1, m_descriptorType, m_updateRegistry.getWriteObjectOffset(2), 0));
7515			break;
7516
7517		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7518			updateEntries.push_back(createTemplateBinding(1, 0, 2, m_descriptorType, m_updateRegistry.getWriteObjectOffset(1), sizeof(texelBufferInfos[0])));
7519			break;
7520
7521		default:
7522			DE_FATAL("Impossible");
7523	}
7524
7525	templateCreateInfo.pDescriptorUpdateEntries		= &updateEntries[0];
7526	templateCreateInfo.descriptorUpdateEntryCount	= (deUint32)updateEntries.size();
7527
7528	m_updateTemplate								= vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
7529
7530	if (!withPush)
7531	{
7532		m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, *m_updateTemplate, m_updateRegistry.getRawPointer());
7533	}
7534}
7535
7536tcu::TestStatus TexelBufferComputeInstance::iterate (void)
7537{
7538	logTestPlan();
7539	return testResourceAccess();
7540}
7541
7542void TexelBufferComputeInstance::logTestPlan (void) const
7543{
7544	std::ostringstream msg;
7545
7546	msg << "Fetching 4 values from image in compute shader.\n"
7547		<< "Single descriptor set. Descriptor set contains "
7548			<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
7549			    (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
7550			    (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
7551			    (const char*)DE_NULL)
7552		<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
7553		<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
7554		<< "Buffer format is " << vk::getFormatName(vk::mapTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
7555
7556	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
7557	{
7558		msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
7559
7560		if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
7561		{
7562			const int srcResourceNdx = (resultNdx % 2); // ABAB source
7563			msg << " from texelBuffer " << srcResourceNdx;
7564		}
7565
7566		msg << "\n";
7567	}
7568
7569	m_context.getTestContext().getLog()
7570		<< tcu::TestLog::Message
7571		<< msg.str()
7572		<< tcu::TestLog::EndMessage;
7573}
7574
7575tcu::TestStatus TexelBufferComputeInstance::testResourceAccess (void)
7576{
7577	const vk::Unique<vk::VkDescriptorSetLayout>		descriptorSetLayout	(createDescriptorSetLayout());
7578	const vk::Unique<vk::VkDescriptorPool>			descriptorPool		(createDescriptorPool());
7579	const vk::Unique<vk::VkDescriptorSet>			descriptorSet		(createDescriptorSet(*descriptorPool, *descriptorSetLayout));
7580	const ComputePipeline							pipeline			(m_vki, m_device, m_context.getBinaryCollection(), 1, &descriptorSetLayout.get());
7581
7582	const vk::VkDescriptorSet						descriptorSets[]	= { *descriptorSet };
7583	const int										numDescriptorSets	= (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE || m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? 0 : DE_LENGTH_OF_ARRAY(descriptorSets);
7584	const deUint32* const							dynamicOffsets		= DE_NULL;
7585	const int										numDynamicOffsets	= 0;
7586	const vk::VkBufferMemoryBarrier* const			preBarriers			= m_texelBuffers.getBufferInitBarriers();
7587	const int										numPreBarriers		= m_texelBuffers.getNumTexelBuffers();
7588	const vk::VkBufferMemoryBarrier* const			postBarriers		= m_result.getResultReadBarrier();
7589	const int										numPostBarriers		= 1;
7590
7591	const ComputeCommand							compute				(m_vki,
7592																		 m_device,
7593																		 pipeline.getPipeline(),
7594																		 pipeline.getPipelineLayout(),
7595																		 tcu::UVec3(4, 1, 1),
7596																		 numDescriptorSets,	descriptorSets,
7597																		 numDynamicOffsets,	dynamicOffsets,
7598																		 numPreBarriers,	preBarriers,
7599																		 numPostBarriers,	postBarriers);
7600
7601	tcu::Vec4										results[4];
7602	bool											anyResultSet		= false;
7603	bool											allResultsOk		= true;
7604
7605	if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7606	{
7607		writeDescriptorSetWithTemplate(DE_NULL, *descriptorSetLayout, true, pipeline.getPipelineLayout());
7608		compute.submitAndWait(m_queueFamilyIndex, m_queue, *m_updateTemplate, (const void*) m_updateRegistry.getRawPointer());
7609	}
7610	else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
7611	{
7612		writeDescriptorSet(DE_NULL);
7613		compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder);
7614	}
7615	else
7616	{
7617		compute.submitAndWait(m_queueFamilyIndex, m_queue);
7618	}
7619	m_result.readResultContentsTo(&results);
7620
7621	// verify
7622	for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
7623	{
7624		const tcu::Vec4	result				= results[resultNdx];
7625		const tcu::Vec4	reference			= m_texelBuffers.fetchTexelValue(resultNdx);
7626		const tcu::Vec4	conversionThreshold	= tcu::Vec4(1.0f / 255.0f);
7627
7628		if (result != tcu::Vec4(-1.0f))
7629			anyResultSet = true;
7630
7631		if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
7632		{
7633			allResultsOk = false;
7634
7635			m_context.getTestContext().getLog()
7636				<< tcu::TestLog::Message
7637				<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
7638				<< tcu::TestLog::EndMessage;
7639		}
7640	}
7641
7642	// read back and verify
7643	if (allResultsOk)
7644		return tcu::TestStatus::pass("Pass");
7645	else if (anyResultSet)
7646		return tcu::TestStatus::fail("Invalid result values");
7647	else
7648	{
7649		m_context.getTestContext().getLog()
7650			<< tcu::TestLog::Message
7651			<< "Result buffer was not written to."
7652			<< tcu::TestLog::EndMessage;
7653		return tcu::TestStatus::fail("Result buffer was not written to");
7654	}
7655}
7656
7657class TexelBufferDescriptorCase : public QuadrantRendederCase
7658{
7659public:
7660	enum
7661	{
7662		FLAG_VIEW_OFFSET = (1u << 1u),
7663	};
7664	// enum continues where resource flags ends
7665	DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
7666
7667								TexelBufferDescriptorCase	(tcu::TestContext&		testCtx,
7668															 DescriptorUpdateMethod	updateMethod,
7669															 const char*			name,
7670															 const char*			description,
7671															 bool					isPrimaryCmdBuf,
7672															 vk::VkDescriptorType	descriptorType,
7673															 vk::VkShaderStageFlags	exitingStages,
7674															 vk::VkShaderStageFlags	activeStages,
7675															 ShaderInputInterface	shaderInterface,
7676															 deUint32				flags);
7677
7678private:
7679	std::string					genExtensionDeclarations	(vk::VkShaderStageFlagBits stage) const;
7680	std::string					genResourceDeclarations		(vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
7681	std::string					genResourceAccessSource		(vk::VkShaderStageFlagBits stage) const;
7682	std::string					genNoAccessSource			(void) const;
7683
7684	vkt::TestInstance*			createInstance				(vkt::Context& context) const;
7685
7686	const DescriptorUpdateMethod	m_updateMethod;
7687	const bool						m_isPrimaryCmdBuf;
7688	const vk::VkDescriptorType		m_descriptorType;
7689	const ShaderInputInterface		m_shaderInterface;
7690	const bool						m_nonzeroViewOffset;
7691};
7692
7693TexelBufferDescriptorCase::TexelBufferDescriptorCase (tcu::TestContext&			testCtx,
7694													  DescriptorUpdateMethod	updateMethod,
7695													  const char*				name,
7696													  const char*				description,
7697													  bool						isPrimaryCmdBuf,
7698													  vk::VkDescriptorType		descriptorType,
7699													  vk::VkShaderStageFlags	exitingStages,
7700													  vk::VkShaderStageFlags	activeStages,
7701													  ShaderInputInterface		shaderInterface,
7702													  deUint32					flags)
7703	: QuadrantRendederCase	(testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages)
7704	, m_updateMethod		(updateMethod)
7705	, m_isPrimaryCmdBuf		(isPrimaryCmdBuf)
7706	, m_descriptorType		(descriptorType)
7707	, m_shaderInterface		(shaderInterface)
7708	, m_nonzeroViewOffset	(((flags & FLAG_VIEW_OFFSET) != 0) ? (1u) : (0u))
7709{
7710}
7711
7712std::string TexelBufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
7713{
7714	DE_UNREF(stage);
7715	return "#extension GL_EXT_texture_buffer : require\n";
7716}
7717
7718std::string TexelBufferDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
7719{
7720	DE_UNREF(stage);
7721
7722	const bool			isUniform		= isUniformDescriptorType(m_descriptorType);
7723	const char* const	storageType		= (isUniform) ? ("samplerBuffer ") : ("readonly imageBuffer ");
7724	const char* const	formatQualifier	= (isUniform) ? ("") : (", rgba8");
7725
7726	switch (m_shaderInterface)
7727	{
7728		case SHADER_INPUT_SINGLE_DESCRIPTOR:
7729			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBuffer;\n";
7730
7731		case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
7732			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBufferA;\n"
7733				   "layout(set = 0, binding = " + de::toString(numUsedBindings+1) + formatQualifier + ") uniform highp " + storageType + " u_texelBufferB;\n";
7734
7735		case SHADER_INPUT_DESCRIPTOR_ARRAY:
7736			return "layout(set = 0, binding = " + de::toString(numUsedBindings) + formatQualifier + ") uniform highp " + storageType + " u_texelBuffer[2];\n";
7737
7738		default:
7739			DE_FATAL("Impossible");
7740			return "";
7741	}
7742}
7743
7744std::string TexelBufferDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
7745{
7746	DE_UNREF(stage);
7747
7748	const char* const	accessPostfixA	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? ("")
7749										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? ("A")
7750										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? ("[0]")
7751										: (DE_NULL);
7752	const char* const	accessPostfixB	= (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)						? ("")
7753										: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)		? ("B")
7754										: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY)						? ("[1]")
7755										: (DE_NULL);
7756	const char* const	fetchFunc		= (isUniformDescriptorType(m_descriptorType)) ? ("texelFetch") : ("imageLoad");
7757	std::ostringstream	buf;
7758
7759	buf << "	if (quadrant_id == 0)\n"
7760		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(0) << ");\n"
7761		<< "	else if (quadrant_id == 1)\n"
7762		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(1) << ");\n"
7763		<< "	else if (quadrant_id == 2)\n"
7764		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(2) << ");\n"
7765		<< "	else\n"
7766		<< "		result_color = " << fetchFunc << "(u_texelBuffer" << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(3) << ");\n";
7767
7768	return buf.str();
7769}
7770
7771std::string TexelBufferDescriptorCase::genNoAccessSource (void) const
7772{
7773	return "	if (quadrant_id == 1 || quadrant_id == 2)\n"
7774			"		result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
7775			"	else\n"
7776			"		result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
7777}
7778
7779vkt::TestInstance* TexelBufferDescriptorCase::createInstance (vkt::Context& context) const
7780{
7781	verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages);
7782
7783	if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
7784	{
7785		DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
7786		return new TexelBufferComputeInstance(context, m_updateMethod, m_descriptorType, m_shaderInterface, m_nonzeroViewOffset);
7787	}
7788	else
7789		return new TexelBufferRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_activeStages, m_shaderInterface, m_nonzeroViewOffset);
7790}
7791
7792void createShaderAccessImageTests (tcu::TestCaseGroup*		group,
7793								   bool						isPrimaryCmdBuf,
7794								   DescriptorUpdateMethod	updateMethod,
7795								   vk::VkDescriptorType		descriptorType,
7796								   vk::VkShaderStageFlags	exitingStages,
7797								   vk::VkShaderStageFlags	activeStages,
7798								   ShaderInputInterface		dimension,
7799								   deUint32					resourceFlags)
7800{
7801	static const struct
7802	{
7803		vk::VkImageViewType	viewType;
7804		const char*			name;
7805		const char*			description;
7806		deUint32			flags;
7807	} s_imageTypes[] =
7808	{
7809		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d",						"1D image view",								0u										},
7810		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d_base_mip",				"1D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
7811		{ vk::VK_IMAGE_VIEW_TYPE_1D,			"1d_base_slice",			"1D image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
7812
7813		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array",					"1D array image view",							0u										},
7814		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array_base_mip",		"1D array image subview with base mip level",	ImageDescriptorCase::FLAG_BASE_MIP		},
7815		{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY,		"1d_array_base_slice",		"1D array image subview with base array slice",	ImageDescriptorCase::FLAG_BASE_SLICE	},
7816
7817		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d",						"2D image view",								0u										},
7818		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d_base_mip",				"2D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
7819		{ vk::VK_IMAGE_VIEW_TYPE_2D,			"2d_base_slice",			"2D image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
7820
7821		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array",					"2D array image view",							0u										},
7822		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array_base_mip",		"2D array image subview with base mip level",	ImageDescriptorCase::FLAG_BASE_MIP		},
7823		{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY,		"2d_array_base_slice",		"2D array image subview with base array slice",	ImageDescriptorCase::FLAG_BASE_SLICE	},
7824
7825		{ vk::VK_IMAGE_VIEW_TYPE_3D,			"3d",						"3D image view",								0u										},
7826		{ vk::VK_IMAGE_VIEW_TYPE_3D,			"3d_base_mip",				"3D image subview with base mip level",			ImageDescriptorCase::FLAG_BASE_MIP		},
7827		// no 3d array textures
7828
7829		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube",						"Cube image view",								0u										},
7830		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube_base_mip",			"Cube image subview with base mip level",		ImageDescriptorCase::FLAG_BASE_MIP		},
7831		{ vk::VK_IMAGE_VIEW_TYPE_CUBE,			"cube_base_slice",			"Cube image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
7832
7833		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array",				"Cube image view",								0u										},
7834		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array_base_mip",		"Cube image subview with base mip level",		ImageDescriptorCase::FLAG_BASE_MIP		},
7835		{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	"cube_array_base_slice",	"Cube image subview with base array slice",		ImageDescriptorCase::FLAG_BASE_SLICE	},
7836	};
7837
7838	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++ndx)
7839	{
7840		// never overlap
7841		DE_ASSERT((s_imageTypes[ndx].flags & resourceFlags) == 0u);
7842
7843
7844		if (dimension == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS)
7845			continue;
7846
7847		// SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS only supported in VK_DESCRIPTOR_TYPE_SAMPLER on graphics shaders for now
7848		if (dimension == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS &&
7849			(descriptorType != vk::VK_DESCRIPTOR_TYPE_SAMPLER || activeStages == vk::VK_SHADER_STAGE_COMPUTE_BIT))
7850			continue;
7851
7852		group->addChild(new ImageDescriptorCase(group->getTestContext(),
7853												s_imageTypes[ndx].name,
7854												s_imageTypes[ndx].description,
7855												isPrimaryCmdBuf,
7856												updateMethod,
7857												descriptorType,
7858												exitingStages,
7859												activeStages,
7860												dimension,
7861												s_imageTypes[ndx].viewType,
7862												s_imageTypes[ndx].flags | resourceFlags));
7863	}
7864}
7865
7866void createShaderAccessTexelBufferTests (tcu::TestCaseGroup*	group,
7867										 bool					isPrimaryCmdBuf,
7868										 DescriptorUpdateMethod	updateMethod,
7869										 vk::VkDescriptorType	descriptorType,
7870										 vk::VkShaderStageFlags	exitingStages,
7871										 vk::VkShaderStageFlags	activeStages,
7872										 ShaderInputInterface	dimension,
7873										 deUint32				resourceFlags)
7874{
7875	DE_ASSERT(resourceFlags == 0);
7876	DE_UNREF(resourceFlags);
7877
7878	static const struct
7879	{
7880		const char*	name;
7881		const char*	description;
7882		deUint32	flags;
7883	} s_texelBufferTypes[] =
7884	{
7885		{ "offset_zero",		"View offset is zero",		0u											},
7886		{ "offset_nonzero",		"View offset is non-zero",	TexelBufferDescriptorCase::FLAG_VIEW_OFFSET	},
7887	};
7888
7889	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_texelBufferTypes); ++ndx)
7890	{
7891		if (dimension == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS || dimension == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS)
7892			continue;
7893
7894		group->addChild(new TexelBufferDescriptorCase(group->getTestContext(),
7895													  updateMethod,
7896													  s_texelBufferTypes[ndx].name,
7897													  s_texelBufferTypes[ndx].description,
7898													  isPrimaryCmdBuf,
7899													  descriptorType,
7900													  exitingStages,
7901													  activeStages,
7902													  dimension,
7903													  s_texelBufferTypes[ndx].flags));
7904	}
7905}
7906
7907void createShaderAccessBufferTests (tcu::TestCaseGroup*		group,
7908									bool					isPrimaryCmdBuf,
7909									DescriptorUpdateMethod	updateMethod,
7910									vk::VkDescriptorType	descriptorType,
7911									vk::VkShaderStageFlags	exitingStages,
7912									vk::VkShaderStageFlags	activeStages,
7913									ShaderInputInterface	dimension,
7914									deUint32				resourceFlags)
7915{
7916	DE_ASSERT(resourceFlags == 0u);
7917	DE_UNREF(resourceFlags);
7918
7919	static const struct
7920	{
7921		const char*	name;
7922		const char*	description;
7923		bool		isForDynamicCases;
7924		deUint32	flags;
7925	} s_bufferTypes[] =
7926	{
7927		{ "offset_view_zero",						"View offset is zero",									false,	0u																							},
7928		{ "offset_view_nonzero",					"View offset is non-zero",								false,	BufferDescriptorCase::FLAG_VIEW_OFFSET														},
7929
7930		{ "offset_view_zero_dynamic_zero",			"View offset is zero, dynamic offset is zero",			true,	BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_ZERO												},
7931		{ "offset_view_zero_dynamic_nonzero",		"View offset is zero, dynamic offset is non-zero",		true,	BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO											},
7932		{ "offset_view_nonzero_dynamic_zero",		"View offset is non-zero, dynamic offset is zero",		true,	BufferDescriptorCase::FLAG_VIEW_OFFSET | BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_ZERO		},
7933		{ "offset_view_nonzero_dynamic_nonzero",	"View offset is non-zero, dynamic offset is non-zero",	true,	BufferDescriptorCase::FLAG_VIEW_OFFSET | BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO	},
7934	};
7935
7936	const bool isDynamicCase = isDynamicDescriptorType(descriptorType);
7937
7938	if (isDynamicCase)
7939	{
7940		if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH || updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
7941		{
7942			// Can't support push descriptor sets with dynamic UBOs or SSBOs
7943			return;
7944		}
7945	}
7946
7947	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_bufferTypes); ++ndx)
7948	{
7949		if (dimension == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS)
7950			continue;
7951
7952		if (isDynamicCase == s_bufferTypes[ndx].isForDynamicCases)
7953			group->addChild(new BufferDescriptorCase(group->getTestContext(),
7954													 updateMethod,
7955													 s_bufferTypes[ndx].name,
7956													 s_bufferTypes[ndx].description,
7957													 isPrimaryCmdBuf,
7958													 descriptorType,
7959													 exitingStages,
7960													 activeStages,
7961													 dimension,
7962													 s_bufferTypes[ndx].flags));
7963	}
7964}
7965
7966} // anonymous
7967
7968tcu::TestCaseGroup* createShaderAccessTests (tcu::TestContext& testCtx)
7969{
7970	static const struct
7971	{
7972		const bool	isPrimary;
7973		const char*	name;
7974		const char*	description;
7975	} s_bindTypes[] =
7976	{
7977		{ true,		"primary_cmd_buf",		"Bind in primary command buffer"	},
7978		{ false,	"secondary_cmd_buf",	"Bind in secondary command buffer"	},
7979	};
7980	static const struct
7981	{
7982		const DescriptorUpdateMethod	method;
7983		const char*						name;
7984		const char*						description;
7985	} s_updateMethods[] =
7986	{
7987		{  DESCRIPTOR_UPDATE_METHOD_NORMAL,				"",						"Use regular descriptor updates" },
7988		{  DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE,		"with_template",		"Use descriptor update templates" },
7989		{  DESCRIPTOR_UPDATE_METHOD_WITH_PUSH,			"with_push",			"Use push descriptor updates" },
7990		{  DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE, "with_push_template",	"Use push descriptor update templates" },
7991	};
7992	static const struct
7993	{
7994		const vk::VkDescriptorType	descriptorType;
7995		const char*					name;
7996		const char*					description;
7997		deUint32					flags;
7998	} s_descriptorTypes[] =
7999	{
8000		{ vk::VK_DESCRIPTOR_TYPE_SAMPLER,					"sampler_mutable",					"VK_DESCRIPTOR_TYPE_SAMPLER with mutable sampler",					0u								},
8001		{ vk::VK_DESCRIPTOR_TYPE_SAMPLER,					"sampler_immutable",				"VK_DESCRIPTOR_TYPE_SAMPLER with immutable sampler",				RESOURCE_FLAG_IMMUTABLE_SAMPLER	},
8002		{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	"combined_image_sampler_mutable",	"VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with mutable sampler",	0u								},
8003		{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,	"combined_image_sampler_immutable",	"VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with immutable sampler",	RESOURCE_FLAG_IMMUTABLE_SAMPLER	},
8004		// \note No way to access SAMPLED_IMAGE without a sampler
8005		//{ vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,				"sampled_image",					"VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE",									0u								},
8006		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,				"storage_image",					"VK_DESCRIPTOR_TYPE_STORAGE_IMAGE",									0u								},
8007		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,		"uniform_texel_buffer",				"VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER",							0u								},
8008		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,		"storage_texel_buffer",				"VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER",							0u								},
8009		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,			"uniform_buffer",					"VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER",								0u								},
8010		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			"storage_buffer",					"VK_DESCRIPTOR_TYPE_STORAGE_BUFFER",								0u								},
8011		{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,	"uniform_buffer_dynamic",			"VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC",						0u								},
8012		{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,	"storage_buffer_dynamic",			"VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC",						0u								},
8013	};
8014	static const struct
8015	{
8016		const char*				name;
8017		const char*				description;
8018		vk::VkShaderStageFlags	existingStages;				//!< stages that exists
8019		vk::VkShaderStageFlags	activeStages;				//!< stages that access resource
8020		bool					supportsSecondaryCmdBufs;
8021	} s_shaderStages[] =
8022	{
8023		{
8024			"no_access",
8025			"No accessing stages",
8026			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8027			0u,
8028			true,
8029		},
8030		{
8031			"vertex",
8032			"Vertex stage",
8033			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8034			vk::VK_SHADER_STAGE_VERTEX_BIT,
8035			true,
8036		},
8037		{
8038			"tess_ctrl",
8039			"Tessellation control stage",
8040			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8041			vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
8042			true,
8043		},
8044		{
8045			"tess_eval",
8046			"Tessellation evaluation stage",
8047			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8048			vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
8049			true,
8050		},
8051		{
8052			"geometry",
8053			"Geometry stage",
8054			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_GEOMETRY_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8055			vk::VK_SHADER_STAGE_GEOMETRY_BIT,
8056			true,
8057		},
8058		{
8059			"fragment",
8060			"Fragment stage",
8061			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8062			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8063			true,
8064		},
8065		{
8066			"compute",
8067			"Compute stage",
8068			vk::VK_SHADER_STAGE_COMPUTE_BIT,
8069			vk::VK_SHADER_STAGE_COMPUTE_BIT,
8070			false,
8071		},
8072		{
8073			"vertex_fragment",
8074			"Vertex and fragment stages",
8075			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8076			vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
8077			true,
8078		},
8079	};
8080	static const struct
8081	{
8082		ShaderInputInterface	dimension;
8083		const char*				name;
8084		const char*				description;
8085	} s_variableDimensions[] =
8086	{
8087		{ SHADER_INPUT_SINGLE_DESCRIPTOR,					"single_descriptor",					"Single descriptor"		},
8088		{ SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS,		"multiple_contiguous_descriptors",		"Multiple descriptors"	},
8089		{ SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS,	"multiple_discontiguous_descriptors",	"Multiple descriptors"	},
8090		{ SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS,		"multiple_arbitrary_descriptors",		"Multiple descriptors"	},
8091		{ SHADER_INPUT_DESCRIPTOR_ARRAY,					"descriptor_array",						"Descriptor array"		},
8092	};
8093
8094	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_access", "Access resource via descriptor in a single descriptor set"));
8095
8096	// .primary_cmd_buf...
8097	for (int bindTypeNdx = 0; bindTypeNdx < DE_LENGTH_OF_ARRAY(s_bindTypes); ++bindTypeNdx)
8098	{
8099		de::MovePtr<tcu::TestCaseGroup> bindGroup(new tcu::TestCaseGroup(testCtx, s_bindTypes[bindTypeNdx].name, s_bindTypes[bindTypeNdx].description));
8100
8101		for (int updateMethodNdx = 0; updateMethodNdx < DE_LENGTH_OF_ARRAY(s_updateMethods); ++updateMethodNdx)
8102		{
8103			de::MovePtr<tcu::TestCaseGroup> updateMethodGroup(new tcu::TestCaseGroup(testCtx, s_updateMethods[updateMethodNdx].name, s_updateMethods[updateMethodNdx].description));
8104
8105			// .sampler, .combined_image_sampler, other resource types ...
8106			for (int descriptorNdx = 0; descriptorNdx < DE_LENGTH_OF_ARRAY(s_descriptorTypes); ++descriptorNdx)
8107			{
8108				de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, s_descriptorTypes[descriptorNdx].name, s_descriptorTypes[descriptorNdx].description));
8109
8110				for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(s_shaderStages); ++stageNdx)
8111				{
8112					if (s_bindTypes[bindTypeNdx].isPrimary || s_shaderStages[stageNdx].supportsSecondaryCmdBufs)
8113					{
8114						de::MovePtr<tcu::TestCaseGroup> stageGroup(new tcu::TestCaseGroup(testCtx, s_shaderStages[stageNdx].name, s_shaderStages[stageNdx].description));
8115
8116						for (int dimensionNdx = 0; dimensionNdx < DE_LENGTH_OF_ARRAY(s_variableDimensions); ++dimensionNdx)
8117						{
8118							de::MovePtr<tcu::TestCaseGroup>	dimensionGroup(new tcu::TestCaseGroup(testCtx, s_variableDimensions[dimensionNdx].name, s_variableDimensions[dimensionNdx].description));
8119							void							(*createTestsFunc)(tcu::TestCaseGroup*		group,
8120																			   bool						isPrimaryCmdBuf,
8121																			   DescriptorUpdateMethod	updateMethod,
8122																			   vk::VkDescriptorType		descriptorType,
8123																			   vk::VkShaderStageFlags	existingStages,
8124																			   vk::VkShaderStageFlags	activeStages,
8125																			   ShaderInputInterface		dimension,
8126																			   deUint32					resourceFlags);
8127
8128							switch (s_descriptorTypes[descriptorNdx].descriptorType)
8129							{
8130								case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
8131								case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
8132								case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
8133									createTestsFunc = createShaderAccessImageTests;
8134									break;
8135
8136								case vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
8137								case vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
8138									createTestsFunc = createShaderAccessTexelBufferTests;
8139									break;
8140
8141								case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
8142								case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
8143								case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
8144								case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
8145									createTestsFunc = createShaderAccessBufferTests;
8146									break;
8147
8148								default:
8149									createTestsFunc = DE_NULL;
8150									DE_FATAL("Impossible");
8151							}
8152
8153							if (createTestsFunc)
8154							{
8155								createTestsFunc(dimensionGroup.get(),
8156										s_bindTypes[bindTypeNdx].isPrimary,
8157										s_updateMethods[updateMethodNdx].method,
8158										s_descriptorTypes[descriptorNdx].descriptorType,
8159										s_shaderStages[stageNdx].existingStages,
8160										s_shaderStages[stageNdx].activeStages,
8161										s_variableDimensions[dimensionNdx].dimension,
8162										s_descriptorTypes[descriptorNdx].flags);
8163							}
8164							else
8165								DE_FATAL("Impossible");
8166
8167							stageGroup->addChild(dimensionGroup.release());
8168						}
8169
8170						typeGroup->addChild(stageGroup.release());
8171					}
8172				}
8173
8174				if (s_updateMethods[updateMethodNdx].method != DESCRIPTOR_UPDATE_METHOD_NORMAL)
8175				{
8176					updateMethodGroup->addChild(typeGroup.release());
8177				}
8178				else
8179				{
8180					bindGroup->addChild(typeGroup.release());
8181				}
8182			}
8183
8184			if (s_updateMethods[updateMethodNdx].method != DESCRIPTOR_UPDATE_METHOD_NORMAL)
8185			{
8186				bindGroup->addChild(updateMethodGroup.release());
8187			}
8188		}
8189
8190		group->addChild(bindGroup.release());
8191	}
8192
8193	return group.release();
8194}
8195
8196} // BindingModel
8197} // vkt
8198