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