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