1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group 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 vktPipelineFramebuferAttachmentTests.cpp
21 * \brief Render to a framebuffer with attachments of different sizes and with
22 *        no attachments at all
23 *
24 *//*--------------------------------------------------------------------*/
25
26#include "vktPipelineFramebufferAttachmentTests.hpp"
27#include "vktPipelineMakeUtil.hpp"
28#include "vktTestCase.hpp"
29#include "vktTestCaseUtil.hpp"
30#include "vktPipelineVertexUtil.hpp"
31#include "vktTestGroupUtil.hpp"
32
33#include "vkMemUtil.hpp"
34#include "vkQueryUtil.hpp"
35#include "vkTypeUtil.hpp"
36#include "vkRefUtil.hpp"
37#include "vkBuilderUtil.hpp"
38#include "vkPrograms.hpp"
39#include "vkImageUtil.hpp"
40
41#include "tcuTextureUtil.hpp"
42#include "tcuImageCompare.hpp"
43
44#include "deUniquePtr.hpp"
45#include "deSharedPtr.hpp"
46
47#include <string>
48#include <vector>
49
50namespace vkt
51{
52namespace pipeline
53{
54namespace
55{
56using namespace vk;
57using de::UniquePtr;
58using de::MovePtr;
59using de::SharedPtr;
60using tcu::IVec3;
61using tcu::Vec4;
62using tcu::UVec4;
63using tcu::IVec4;
64using std::vector;
65
66static const VkFormat COLOR_FORMAT	=		VK_FORMAT_R8G8B8A8_UNORM;
67
68typedef SharedPtr<Unique<VkImageView> >	SharedPtrVkImageView;
69typedef SharedPtr<Unique<VkPipeline> >	SharedPtrVkPipeline;
70
71struct CaseDef
72{
73	VkImageViewType	imageType;
74	IVec3			renderSize;
75	IVec3			attachmentSize;
76	deUint32		numLayers;
77	bool			multisample;
78};
79
80template<typename T>
81inline SharedPtr<Unique<T> > makeSharedPtr(Move<T> move)
82{
83	return SharedPtr<Unique<T> >(new Unique<T>(move));
84}
85
86template<typename T>
87inline VkDeviceSize sizeInBytes(const vector<T>& vec)
88{
89	return vec.size() * sizeof(vec[0]);
90}
91
92VkImageType getImageType(const VkImageViewType viewType)
93{
94	switch (viewType)
95	{
96		case VK_IMAGE_VIEW_TYPE_1D:
97		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
98			return VK_IMAGE_TYPE_1D;
99
100		case VK_IMAGE_VIEW_TYPE_2D:
101		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
102		case VK_IMAGE_VIEW_TYPE_CUBE:
103		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
104			return VK_IMAGE_TYPE_2D;
105
106		case VK_IMAGE_VIEW_TYPE_3D:
107			return VK_IMAGE_TYPE_3D;
108
109		default:
110			DE_ASSERT(0);
111			return VK_IMAGE_TYPE_LAST;
112	}
113}
114
115//! Make a render pass with one subpass per color attachment and one attachment per image layer.
116Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk,
117								   const VkDevice		  device,
118								   const VkFormat		  colorFormat,
119								   const deUint32		  numLayers,
120								   const bool			  multisample)
121{
122	vector<VkAttachmentDescription>	attachmentDescriptions		(numLayers);
123	deUint32						attachmentIndex				= 0;
124	vector<VkAttachmentReference>	colorAttachmentReferences	(numLayers);
125	vector<VkSubpassDescription>	subpasses;
126
127	for (deUint32 i = 0; i < numLayers; i++)
128	{
129		VkAttachmentDescription colorAttachmentDescription =
130		{
131			(VkAttachmentDescriptionFlags)0,								// VkAttachmentDescriptionFla	flags;
132			colorFormat,													// VkFormat						format;
133			!multisample ? VK_SAMPLE_COUNT_1_BIT : VK_SAMPLE_COUNT_4_BIT,	// VkSampleCountFlagBits		samples;
134			VK_ATTACHMENT_LOAD_OP_LOAD,										// VkAttachmentLoadOp			loadOp;
135			VK_ATTACHMENT_STORE_OP_STORE,									// VkAttachmentStoreOp			storeOp;
136			VK_ATTACHMENT_LOAD_OP_DONT_CARE,								// VkAttachmentLoadOp			stencilLoadOp;
137			VK_ATTACHMENT_STORE_OP_DONT_CARE,								// VkAttachmentStoreOp			stencilStoreOp;
138			VK_IMAGE_LAYOUT_GENERAL,										// VkImageLayout				initialLayout;
139			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,						// VkImageLayout				finalLayout;
140		};
141		attachmentDescriptions[attachmentIndex++] = colorAttachmentDescription;
142	}
143
144	// Create a subpass for each attachment (each attachment is a layer of an arrayed image).
145	for (deUint32 i = 0; i < numLayers; ++i)
146	{
147		const VkAttachmentReference attachmentRef =
148		{
149			i,											// deUint32			attachment;
150			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
151		};
152		colorAttachmentReferences[i] = attachmentRef;
153
154		const VkSubpassDescription subpassDescription =
155		{
156			(VkSubpassDescriptionFlags)0,		// VkSubpassDescriptionFlags		flags;
157			VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint				pipelineBindPoint;
158			0u,									// deUint32							inputAttachmentCount;
159			DE_NULL,							// const VkAttachmentReference*		pInputAttachments;
160			1u,									// deUint32							colorAttachmentCount;
161			&colorAttachmentReferences[i],		// const VkAttachmentReference*		pColorAttachments;
162			DE_NULL,							// const VkAttachmentReference*		pResolveAttachments;
163			DE_NULL,							// const VkAttachmentReference*		pDepthStencilAttachment;
164			0u,									// deUint32							preserveAttachmentCount;
165			DE_NULL								// const deUint32*					pPreserveAttachments;
166		};
167		subpasses.push_back(subpassDescription);
168	}
169
170	const VkRenderPassCreateInfo renderPassInfo =
171	{
172		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	// VkStructureType					sType;
173		DE_NULL,									// const void*						pNext;
174		(VkRenderPassCreateFlags)0,					// VkRenderPassCreateFlags			flags;
175		numLayers,									// deUint32							attachmentCount;
176		&attachmentDescriptions[0],					// const VkAttachmentDescription*	pAttachments;
177		static_cast<deUint32>(subpasses.size()),	// deUint32							subpassCount;
178		&subpasses[0],								// const VkSubpassDescription*		pSubpasses;
179		0u,											// deUint32							dependencyCount;
180		DE_NULL										// const VkSubpassDependency*		pDependencies;
181	};
182
183	return createRenderPass(vk, device, &renderPassInfo);
184}
185
186Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
187									   const VkDevice				device,
188									   const VkPipelineLayout		pipelineLayout,
189									   const VkRenderPass			renderPass,
190									   const VkShaderModule			vertexModule,
191									   const VkShaderModule			fragmentModule,
192									   const IVec3					renderSize,
193									   const VkPrimitiveTopology	topology,
194									   const deUint32				subpass,
195									   const bool					hasAttachments,
196									   const bool					multisample)
197{
198	const VkVertexInputBindingDescription vertexInputBindingDescription =
199	{
200		0u,								// uint32_t				binding;
201		sizeof(tcu::Vec4),				// uint32_t				stride;
202		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
203	};
204
205	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
206	{
207		{
208			0u,								// uint32_t		location;
209			0u,								// uint32_t		binding;
210			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat		format;
211			0u,								// uint32_t		offset;
212		},
213	};
214
215	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
216	{
217		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType							sType;
218		DE_NULL,													// const void*								pNext;
219		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags	flags;
220		1u,															// uint32_t									vertexBindingDescriptionCount;
221		&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
222		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),		// uint32_t									vertexAttributeDescriptionCount;
223		vertexInputAttributeDescriptions,							// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
224	};
225
226	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
227	{
228		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType;
229		DE_NULL,														// const void*								pNext;
230		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags	flags;
231		topology,														// VkPrimitiveTopology						topology;
232		VK_FALSE,														// VkBool32									primitiveRestartEnable;
233	};
234
235	const VkViewport viewport = makeViewport(
236		0.0f, 0.0f,
237		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
238		0.0f, 1.0f);
239
240	// We must set the scissor rect to the renderSize, since the renderArea specified
241	// during the begin render pass command does not ensure that rendering is strictly
242	// limited to the rect provided there and the spec clearly states that the scissor
243	// must be configured appropriately to ensure this
244	const VkRect2D scissor =
245	{
246		makeOffset2D(0, 0),
247		makeExtent2D(renderSize.x(), renderSize.y()),
248	};
249
250	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
251	{
252		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType						sType;
253		DE_NULL,												// const void*							pNext;
254		(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags	flags;
255		1u,														// uint32_t								viewportCount;
256		&viewport,												// const VkViewport*					pViewports;
257		1u,														// uint32_t								scissorCount;
258		&scissor,												// const VkRect2D*						pScissors;
259	};
260
261	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
262	{
263		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	// VkStructureType							sType;
264		DE_NULL,													// const void*								pNext;
265		(VkPipelineRasterizationStateCreateFlags)0,					// VkPipelineRasterizationStateCreateFlags	flags;
266		VK_FALSE,													// VkBool32									depthClampEnable;
267		VK_FALSE,													// VkBool32									rasterizerDiscardEnable;
268		VK_POLYGON_MODE_FILL,										// VkPolygonMode							polygonMode;
269		VK_CULL_MODE_NONE,											// VkCullModeFlags							cullMode;
270		VK_FRONT_FACE_COUNTER_CLOCKWISE,							// VkFrontFace								frontFace;
271		VK_FALSE,													// VkBool32									depthBiasEnable;
272		0.0f,														// float									depthBiasConstantFactor;
273		0.0f,														// float									depthBiasClamp;
274		0.0f,														// float									depthBiasSlopeFactor;
275		1.0f,														// float									lineWidth;
276	};
277
278	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
279	{
280		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
281		DE_NULL,														// const void*								pNext;
282		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
283		!multisample ? VK_SAMPLE_COUNT_1_BIT : VK_SAMPLE_COUNT_4_BIT,	// VkSampleCountFlagBits					rasterizationSamples;
284		!multisample ? VK_FALSE : VK_TRUE,								// VkBool32									sampleShadingEnable;
285		1.0f,															// float									minSampleShading;
286		DE_NULL,														// const VkSampleMask*						pSampleMask;
287		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
288		VK_FALSE														// VkBool32									alphaToOneEnable;
289	};
290
291	const VkStencilOpState stencilOpState = makeStencilOpState(
292		VK_STENCIL_OP_KEEP,		// stencil fail
293		VK_STENCIL_OP_KEEP,		// depth & stencil pass
294		VK_STENCIL_OP_KEEP,		// depth only fail
295		VK_COMPARE_OP_ALWAYS,	// compare op
296		0u,						// compare mask
297		0u,						// write mask
298		0u);					// reference
299
300	const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
301	{
302		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
303		DE_NULL,													// const void*								pNext;
304		(VkPipelineDepthStencilStateCreateFlags)0,					// VkPipelineDepthStencilStateCreateFlags	flags;
305		VK_FALSE,													// VkBool32									depthTestEnable;
306		VK_FALSE,													// VkBool32									depthWriteEnable;
307		VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
308		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
309		VK_FALSE,													// VkBool32									stencilTestEnable;
310		stencilOpState,												// VkStencilOpState							front;
311		stencilOpState,												// VkStencilOpState							back;
312		0.0f,														// float									minDepthBounds;
313		1.0f,														// float									maxDepthBounds;
314	};
315
316	const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
317	// Number of blend attachments must equal the number of color attachments during any subpass.
318	const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
319	{
320		VK_FALSE,					// VkBool32					blendEnable;
321		VK_BLEND_FACTOR_ONE,		// VkBlendFactor			srcColorBlendFactor;
322		VK_BLEND_FACTOR_ZERO,		// VkBlendFactor			dstColorBlendFactor;
323		VK_BLEND_OP_ADD,			// VkBlendOp				colorBlendOp;
324		VK_BLEND_FACTOR_ONE,		// VkBlendFactor			srcAlphaBlendFactor;
325		VK_BLEND_FACTOR_ZERO,		// VkBlendFactor			dstAlphaBlendFactor;
326		VK_BLEND_OP_ADD,			// VkBlendOp				alphaBlendOp;
327		colorComponentsAll,			// VkColorComponentFlags	colorWriteMask;
328	};
329
330	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
331	{
332		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
333		DE_NULL,													// const void*									pNext;
334		(VkPipelineColorBlendStateCreateFlags)0,					// VkPipelineColorBlendStateCreateFlags			flags;
335		VK_FALSE,													// VkBool32										logicOpEnable;
336		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
337		hasAttachments ? 1u : 0u,									// deUint32										attachmentCount;
338		&pipelineColorBlendAttachmentState,							// const VkPipelineColorBlendAttachmentState*	pAttachments;
339		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConstants[4];
340	};
341
342	const VkPipelineShaderStageCreateInfo pShaderStages[] =
343	{
344		{
345			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
346			DE_NULL,												// const void*							pNext;
347			(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
348			VK_SHADER_STAGE_VERTEX_BIT,								// VkShaderStageFlagBits				stage;
349			vertexModule,											// VkShaderModule						module;
350			"main",													// const char*							pName;
351			DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
352		},
353		{
354			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
355			DE_NULL,												// const void*							pNext;
356			(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
357			VK_SHADER_STAGE_FRAGMENT_BIT,							// VkShaderStageFlagBits				stage;
358			fragmentModule,											// VkShaderModule						module;
359			"main",													// const char*							pName;
360			DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
361		}
362	};
363
364	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
365	{
366		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
367		DE_NULL,											// const void*										pNext;
368		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
369		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
370		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
371		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
372		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
373		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
374		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
375		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
376		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
377		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
378		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
379		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
380		pipelineLayout,										// VkPipelineLayout									layout;
381		renderPass,											// VkRenderPass										renderPass;
382		subpass,											// deUint32											subpass;
383		DE_NULL,											// VkPipeline										basePipelineHandle;
384		0,													// deInt32											basePipelineIndex;
385	};
386
387	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
388}
389
390Move<VkImage> makeImage (const DeviceInterface&		vk,
391						 const VkDevice				device,
392						 const VkImageCreateFlags	flags,
393						 const VkImageType			imageType,
394						 const VkFormat				format,
395						 const IVec3&				size,
396						 const deUint32				numLayers,
397						 const VkImageUsageFlags	usage,
398						 const bool					multisample)
399{
400	const VkImageCreateInfo imageParams =
401	{
402		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,							// VkStructureType			sType;
403		DE_NULL,														// const void*				pNext;
404		flags,															// VkImageCreateFlags		flags;
405		imageType,														// VkImageType				imageType;
406		format,															// VkFormat					format;
407		makeExtent3D(size),												// VkExtent3D				extent;
408		1u,																// deUint32					mipLevels;
409		numLayers,														// deUint32					arrayLayers;
410		multisample ? VK_SAMPLE_COUNT_4_BIT : VK_SAMPLE_COUNT_1_BIT,	// VkSampleCountFlagBits	samples;
411		VK_IMAGE_TILING_OPTIMAL,										// VkImageTiling			tiling;
412		usage,															// VkImageUsageFlags		usage;
413		VK_SHARING_MODE_EXCLUSIVE,										// VkSharingMode			sharingMode;
414		0u,																// deUint32					queueFamilyIndexCount;
415		DE_NULL,														// const deUint32*			pQueueFamilyIndices;
416		VK_IMAGE_LAYOUT_UNDEFINED,										// VkImageLayout			initialLayout;
417	};
418
419	return createImage(vk, device, &imageParams);
420}
421
422vector<tcu::Vec4> genFullQuadVertices (const int subpassCount)
423{
424	vector<tcu::Vec4>	vectorData;
425	for (int subpassNdx = 0; subpassNdx < subpassCount; ++subpassNdx)
426	{
427		vectorData.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
428		vectorData.push_back(Vec4(-1.0f,  1.0f, 0.0f, 1.0f));
429		vectorData.push_back(Vec4(1.0f, -1.0f, 0.0f, 1.0f));
430		vectorData.push_back(Vec4(1.0f,  1.0f, 0.0f, 1.0f));
431	}
432	return vectorData;
433}
434
435void initColorPrograms (SourceCollections& programCollection, const CaseDef caseDef)
436{
437	(void)caseDef;
438
439	// Vertex shader
440	{
441		std::ostringstream src;
442		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
443			<< "\n"
444			<< "layout(location = 0) in vec4 in_position;\n"
445			<< "\n"
446			<< "out gl_PerVertex {\n"
447			<< "	vec4 gl_Position;\n"
448			<< "};\n"
449			<< "\n"
450			<< "void main(void)\n"
451			<< "{\n"
452			<< "	gl_Position	= in_position;\n"
453			<< "}\n";
454
455		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
456	}
457
458	// Fragment shader
459	{
460		std::ostringstream src;
461		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
462			<< "\n"
463			<< "layout(location = 0) out vec4 o_color;\n"
464			<< "\n"
465			<< "void main(void)\n"
466			<< "{\n"
467			<< "    o_color = vec4(1.0, 0.5, 0.25, 1.0);\n"
468			<< "}\n";
469
470		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
471	}
472}
473
474tcu::PixelBufferAccess getExpectedData (tcu::TextureLevel& textureLevel, const CaseDef& caseDef)
475{
476	const tcu::PixelBufferAccess	expectedImage	(textureLevel);
477	const int						renderDepth		= deMax32(caseDef.renderSize.z(), caseDef.numLayers);
478
479	for (int z = 0; z < expectedImage.getDepth(); ++z)
480	{
481		for (int y = 0; y < expectedImage.getHeight(); ++y)
482		{
483			for (int x = 0; x < expectedImage.getWidth(); ++x)
484			{
485				if (x < caseDef.renderSize.x() && y < caseDef.renderSize.y() && z < renderDepth)
486					expectedImage.setPixel(tcu::Vec4(1.0, 0.5, 0.25, 1.0), x, y, z);
487				else
488					expectedImage.setPixel(tcu::Vec4(0.0, 0.0, 0.0, 1.0), x, y, z);
489			}
490		}
491	}
492	return expectedImage;
493}
494
495inline Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize bufferSize, const VkBufferUsageFlags usage)
496{
497	const VkBufferCreateInfo	bufferCreateInfo	= makeBufferCreateInfo(bufferSize, usage);
498	return createBuffer(vk, device, &bufferCreateInfo);
499}
500
501inline VkImageSubresourceRange makeColorSubresourceRange (const deUint32 baseArrayLayer, const deUint32 layerCount)
502{
503	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, baseArrayLayer, layerCount);
504}
505
506// Tests rendering to a a framebuffer with color attachments larger than the
507// framebuffer dimensions and verifies that rendering does not affect the areas
508// of the attachment outside the framebuffer dimensions. Tests both single-sample
509// and multi-sample configurations.
510tcu::TestStatus test (Context& context, const CaseDef caseDef)
511{
512	const DeviceInterface&			vk					= context.getDeviceInterface();
513	const VkDevice					device				= context.getDevice();
514	const VkQueue					queue				= context.getUniversalQueue();
515	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
516	Allocator&						allocator			= context.getDefaultAllocator();
517
518	// Color image for rendering in single-sample tests or resolve target for multi-sample tests
519	Move<VkImage>					colorImage;
520	MovePtr<Allocation>				colorImageAlloc;
521
522	// For multisampled tests, this is the rendering target
523	Move<VkImage>					msColorImage;
524	MovePtr<Allocation>				msColorImageAlloc;
525
526	// Host memory buffer where we will copy the rendered image for verification
527	const deUint32					att_size_x			= caseDef.attachmentSize.x();
528	const deUint32					att_size_y			= caseDef.attachmentSize.y();
529	const deUint32					att_size_z			= caseDef.attachmentSize.z();
530	const VkDeviceSize				colorBufferSize		= att_size_x * att_size_y * att_size_z * caseDef.numLayers * tcu::getPixelSize(mapVkFormat(COLOR_FORMAT));
531	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
532	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
533
534	Move<VkBuffer>					vertexBuffer;
535	MovePtr<Allocation>				vertexBufferAlloc;
536
537	vector<SharedPtrVkImageView>	colorAttachments;
538	vector<VkImageView>				attachmentHandles;
539
540	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device));
541	vector<SharedPtrVkPipeline>		pipeline;
542	const Unique<VkRenderPass>		renderPass			(makeRenderPass(vk, device, COLOR_FORMAT, caseDef.numLayers, caseDef.multisample));
543	Move<VkFramebuffer>				framebuffer;
544
545	const Unique<VkShaderModule>	vertexModule		(createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
546	const Unique<VkShaderModule>	fragmentModule		(createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
547
548	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
549	const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
550
551	const VkImageViewType			imageViewType		= caseDef.imageType == VK_IMAGE_VIEW_TYPE_CUBE || caseDef.imageType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY
552		? VK_IMAGE_VIEW_TYPE_2D : caseDef.imageType;
553
554	// create vertexBuffer
555	{
556		const vector<tcu::Vec4>	vertices			= genFullQuadVertices(caseDef.numLayers);
557		const VkDeviceSize		vertexBufferSize	= sizeInBytes(vertices);
558
559		vertexBuffer		= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
560		vertexBufferAlloc	= bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
561
562		deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
563		flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
564	}
565
566	// create colorImage (and msColorImage) using the configured attachmentsize
567	{
568		const VkImageUsageFlags	colorImageUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
569
570		colorImage		= makeImage(vk, device, VkImageViewCreateFlags(0), getImageType(caseDef.imageType), COLOR_FORMAT,
571			caseDef.attachmentSize, caseDef.numLayers, colorImageUsage, false);
572		colorImageAlloc	= bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any);
573
574		if (caseDef.multisample)
575		{
576			const VkImageUsageFlags	msImageUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
577
578			msColorImage		= makeImage(vk, device, VkImageViewCreateFlags(0), getImageType(caseDef.imageType), COLOR_FORMAT,
579				caseDef.attachmentSize, caseDef.numLayers, msImageUsage, true);
580			msColorImageAlloc	= bindImage(vk, device, allocator, *msColorImage, MemoryRequirement::Any);
581		}
582	}
583
584	// create attachmentHandles and pipelines (one for each layer). We use the renderSize for viewport and scissor
585	for (deUint32 layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
586	{
587		colorAttachments.push_back(makeSharedPtr(makeImageView(vk, device, ! caseDef.multisample ? *colorImage : *msColorImage,
588			imageViewType, COLOR_FORMAT, makeColorSubresourceRange(layerNdx, 1))));
589		attachmentHandles.push_back(**colorAttachments.back());
590
591		pipeline.push_back(makeSharedPtr(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
592			caseDef.renderSize, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, layerNdx, true, caseDef.multisample)));
593	}
594
595	// create framebuffer
596	framebuffer = makeFramebuffer(vk, device, *renderPass, caseDef.numLayers, &attachmentHandles[0],
597		static_cast<deUint32>(caseDef.renderSize.x()), static_cast<deUint32>(caseDef.renderSize.y()));
598
599	// record command buffer
600	beginCommandBuffer(vk, *cmdBuffer);
601	{
602		// Clear the entire image attachment to black
603		{
604			const VkImageMemoryBarrier	imageLayoutBarriers[]	=
605			{
606				{
607					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// VkStructureType			sType;
608					DE_NULL,											// const void*				pNext;
609					0u,													// VkAccessFlags			srcAccessMask;
610					VK_ACCESS_TRANSFER_WRITE_BIT,						// VkAccessFlags			dstAccessMask;
611					VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout			oldLayout;
612					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,				// VkImageLayout			newLayout;
613					VK_QUEUE_FAMILY_IGNORED,							// deUint32					srcQueueFamilyIndex;
614					VK_QUEUE_FAMILY_IGNORED,							// deUint32					destQueueFamilyIndex;
615					caseDef.multisample ? *msColorImage : *colorImage,	// VkImage					image;
616					makeColorSubresourceRange(0, caseDef.numLayers)		// VkImageSubresourceRange	subresourceRange;
617				},
618			};
619
620			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0u,
621				0u, DE_NULL, 0u, DE_NULL, 1u, imageLayoutBarriers);
622
623			const VkImageSubresourceRange	ranges		= makeColorSubresourceRange(0, caseDef.numLayers);
624			const VkClearColorValue			clearColor	=
625	        {
626                {0.0f, 0.0f, 0.0f, 1.0f}
627			};
628			vk.cmdClearColorImage(*cmdBuffer, caseDef.multisample ? *msColorImage : *colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1u, &ranges);
629
630			const VkImageMemoryBarrier	imageClearBarriers[]	=
631			{
632				{
633					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// VkStructureType			sType;
634					DE_NULL,											// const void*				pNext;
635					VK_ACCESS_TRANSFER_WRITE_BIT,						// VkAccessFlags			srcAccessMask;
636					VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,				// VkAccessFlags			dstAccessMask;
637					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,				// VkImageLayout			oldLayout;
638					VK_IMAGE_LAYOUT_GENERAL,							// VkImageLayout			newLayout;
639					VK_QUEUE_FAMILY_IGNORED,							// deUint32					srcQueueFamilyIndex;
640					VK_QUEUE_FAMILY_IGNORED,							// deUint32					destQueueFamilyIndex;
641					caseDef.multisample ? *msColorImage : *colorImage,	// VkImage					image;
642					makeColorSubresourceRange(0, caseDef.numLayers)		// VkImageSubresourceRange	subresourceRange;
643				},
644			};
645
646			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
647				0u, DE_NULL, 0u, DE_NULL, 1u, imageClearBarriers);
648		}
649
650		// Render pass: this should render only to the area defined by renderSize (smaller than the size of the attachment)
651		{
652			const VkRect2D				renderArea			=
653			{
654				makeOffset2D(0, 0),
655				makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
656			};
657			const VkRenderPassBeginInfo renderPassBeginInfo =
658			{
659				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// VkStructureType         sType;
660				DE_NULL,									// const void*             pNext;
661				*renderPass,								// VkRenderPass            renderPass;
662				*framebuffer,								// VkFramebuffer           framebuffer;
663				renderArea,									// VkRect2D                renderArea;
664				0,											// uint32_t                clearValueCount;
665				DE_NULL,									// const VkClearValue*     pClearValues;
666			};
667			const VkDeviceSize			vertexBufferOffset	= 0ull;
668
669			vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
670			{
671				vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
672				for (deUint32 layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
673				{
674					if (layerNdx != 0)
675						vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
676
677					vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipeline[layerNdx]);
678					vk.cmdDraw(*cmdBuffer, 4u, 1u, layerNdx*4u, 0u);
679				}
680			}
681			vk.cmdEndRenderPass(*cmdBuffer);
682		}
683
684		// If we are using a multi-sampled render target (msColorImage), resolve it now (to colorImage)
685		if (caseDef.multisample)
686		{
687			// Transition msColorImage (from layout COLOR_ATTACHMENT_OPTIMAL) and colorImage (from layout UNDEFINED) to layout GENERAL before resolving
688			const VkImageMemoryBarrier	imageBarriers[]	=
689			{
690				{
691					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
692					DE_NULL,										// const void*				pNext;
693					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags			srcAccessMask;
694					VK_ACCESS_TRANSFER_READ_BIT,					// VkAccessFlags			dstAccessMask;
695					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout			oldLayout;
696					VK_IMAGE_LAYOUT_GENERAL,						// VkImageLayout			newLayout;
697					VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
698					VK_QUEUE_FAMILY_IGNORED,						// deUint32					destQueueFamilyIndex;
699					*msColorImage,									// VkImage					image;
700					makeColorSubresourceRange(0, caseDef.numLayers)	// VkImageSubresourceRange	subresourceRange;
701				},
702				{
703					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
704					DE_NULL,										// const void*				pNext;
705					(VkAccessFlags)0,								// VkAccessFlags			srcAccessMask;
706					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags			dstAccessMask;
707					VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			oldLayout;
708					VK_IMAGE_LAYOUT_GENERAL,						// VkImageLayout			newLayout;
709					VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
710					VK_QUEUE_FAMILY_IGNORED,						// deUint32					destQueueFamilyIndex;
711					*colorImage,									// VkImage					image;
712					makeColorSubresourceRange(0, caseDef.numLayers)	// VkImageSubresourceRange	subresourceRange;
713				}
714			};
715
716			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
717				0u, DE_NULL, 0u, DE_NULL, 2u, imageBarriers);
718
719			const VkImageResolve	region	=
720			{
721				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, caseDef.numLayers),	// VkImageSubresourceLayers    srcSubresource;
722				makeOffset3D(0, 0, 0),															// VkOffset3D                  srcOffset;
723				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, caseDef.numLayers),	// VkImageSubresourceLayers    dstSubresource;
724				makeOffset3D(0, 0, 0),															// VkOffset3D                  dstOffset;
725				makeExtent3D(caseDef.attachmentSize)											// VkExtent3D                  extent;
726			};
727
728			vk.cmdResolveImage(*cmdBuffer, *msColorImage, VK_IMAGE_LAYOUT_GENERAL, *colorImage, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
729		}
730
731		// copy colorImage to host visible colorBuffer
732		{
733			const VkImageMemoryBarrier	imageBarriers[]		=
734			{
735				{
736					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,														// VkStructureType			sType;
737					DE_NULL,																					// const void*				pNext;
738					(vk::VkAccessFlags)(caseDef.multisample ? VK_ACCESS_TRANSFER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
739					VK_ACCESS_TRANSFER_READ_BIT,																// VkAccessFlags			dstAccessMask;
740					caseDef.multisample ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			oldLayout;
741					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,														// VkImageLayout			newLayout;
742					VK_QUEUE_FAMILY_IGNORED,																	// deUint32					srcQueueFamilyIndex;
743					VK_QUEUE_FAMILY_IGNORED,																	// deUint32					destQueueFamilyIndex;
744					*colorImage,																				// VkImage					image;
745					makeColorSubresourceRange(0, caseDef.numLayers)												// VkImageSubresourceRange	subresourceRange;
746				}
747			};
748
749			vk.cmdPipelineBarrier(*cmdBuffer, caseDef.multisample ? VK_PIPELINE_STAGE_TRANSFER_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
750				0u, DE_NULL, 0u, DE_NULL, 1u, imageBarriers);
751
752			const VkBufferImageCopy		region				=
753			{
754				0ull,																				// VkDeviceSize                bufferOffset;
755				0u,																					// uint32_t                    bufferRowLength;
756				0u,																					// uint32_t                    bufferImageHeight;
757				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, caseDef.numLayers),	// VkImageSubresourceLayers    imageSubresource;
758				makeOffset3D(0, 0, 0),																// VkOffset3D                  imageOffset;
759				makeExtent3D(caseDef.attachmentSize),												// VkExtent3D                  imageExtent;
760			};
761
762			vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
763
764			const VkBufferMemoryBarrier	bufferBarriers[]	=
765			{
766				{
767					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType    sType;
768					DE_NULL,									// const void*        pNext;
769					VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags      srcAccessMask;
770					VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags      dstAccessMask;
771					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           srcQueueFamilyIndex;
772					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           dstQueueFamilyIndex;
773					*colorBuffer,								// VkBuffer           buffer;
774					0ull,										// VkDeviceSize       offset;
775					VK_WHOLE_SIZE,								// VkDeviceSize       size;
776				},
777			};
778
779			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
780				0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
781		}
782	} // beginCommandBuffer
783
784	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
785	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
786
787	// Verify results
788	{
789		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
790		const tcu::TextureFormat			format			= mapVkFormat(COLOR_FORMAT);
791		const int							depth			= deMax32(caseDef.attachmentSize.z(), caseDef.numLayers);
792		tcu::TextureLevel					textureLevel	(format, caseDef.attachmentSize.x(), caseDef.attachmentSize.y(), depth);
793		const tcu::PixelBufferAccess		expectedImage	= getExpectedData(textureLevel, caseDef);
794		const tcu::ConstPixelBufferAccess	resultImage		(format, caseDef.attachmentSize.x(), caseDef.attachmentSize.y(), depth, colorBufferAlloc->getHostPtr());
795
796		if (!tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT))
797			return tcu::TestStatus::fail("Fail");
798	}
799
800	return tcu::TestStatus::pass("Pass");
801}
802
803void initImagePrograms (SourceCollections& programCollection, const bool multisample)
804{
805	// Vertex shader
806	{
807		std::ostringstream src;
808		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
809			<< "\n"
810			<< "layout(location = 0) in vec4 in_position;\n"
811			<< "\n"
812			<< "out gl_PerVertex {\n"
813			<< "	vec4 gl_Position;\n"
814			<< "};\n"
815			<< "\n"
816			<< "void main(void)\n"
817			<< "{\n"
818			<< "	gl_Position	= in_position;\n"
819			<< "}\n";
820
821		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
822	}
823
824	// Fragment shader
825	{
826		std::ostringstream src;
827		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
828			<< "\n"
829			<< "layout(binding = 0, rgba8) writeonly uniform image2D image;\n"
830			<< "\n"
831			<< "void main(void)\n"
832			<< "{\n";
833			if (!multisample)
834				src << "    imageStore(image, ivec2(gl_PrimitiveID % 4, 0), vec4(1.0, 0.5, 0.25, 1.0));\n";
835			else
836				src << "    imageStore(image, ivec2(gl_PrimitiveID % 4, gl_SampleID % 4), vec4(1.0, 0.5, 0.25, 1.0));\n";
837			src << "}\n";
838
839		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
840	}
841}
842
843//! Make a render pass with no attachments
844Move<VkRenderPass> makeRenderPassNoAtt (const DeviceInterface& vk, const VkDevice device)
845{
846	// Create a single subpass with no attachment references
847	vector<VkSubpassDescription>	subpasses;
848
849	const VkSubpassDescription		subpassDescription	=
850	{
851		(VkSubpassDescriptionFlags)0,		// VkSubpassDescriptionFlags		flags;
852		VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint				pipelineBindPoint;
853		0u,									// deUint32							inputAttachmentCount;
854		DE_NULL,							// const VkAttachmentReference*		pInputAttachments;
855		0u,									// deUint32							colorAttachmentCount;
856		DE_NULL,							// const VkAttachmentReference*		pColorAttachments;
857		DE_NULL,							// const VkAttachmentReference*		pResolveAttachments;
858		DE_NULL,							// const VkAttachmentReference*		pDepthStencilAttachment;
859		0u,									// deUint32							preserveAttachmentCount;
860		DE_NULL								// const deUint32*					pPreserveAttachments;
861	};
862	subpasses.push_back(subpassDescription);
863
864	const VkRenderPassCreateInfo	renderPassInfo	=
865	{
866		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	// VkStructureType					sType;
867		DE_NULL,									// const void*						pNext;
868		(VkRenderPassCreateFlags)0,					// VkRenderPassCreateFlags			flags;
869		0,											// deUint32							attachmentCount;
870		DE_NULL,									// const VkAttachmentDescription*	pAttachments;
871		1,											// deUint32							subpassCount;
872		&subpasses[0],								// const VkSubpassDescription*		pSubpasses;
873		0u,											// deUint32							dependencyCount;
874		DE_NULL										// const VkSubpassDependency*		pDependencies;
875	};
876
877	return createRenderPass(vk, device, &renderPassInfo);
878}
879
880tcu::PixelBufferAccess getExpectedDataNoAtt (tcu::TextureLevel& textureLevel)
881{
882	const tcu::PixelBufferAccess	expectedImage	(textureLevel);
883	for (int z = 0; z < expectedImage.getDepth(); ++z)
884	{
885		for (int y = 0; y < expectedImage.getHeight(); ++y)
886		{
887			for (int x = 0; x < expectedImage.getWidth(); ++x)
888			{
889				expectedImage.setPixel(tcu::Vec4(1.0, 0.5, 0.25, 1.0), x, y, z);
890			}
891		}
892	}
893	return expectedImage;
894}
895
896vector<tcu::Vec4> genPointVertices (void)
897{
898	vector<tcu::Vec4>	vectorData;
899	vectorData.push_back(Vec4(-0.25f, -0.25f, 0, 1));
900	vectorData.push_back(Vec4(-0.25f,  0.25f, 0, 1));
901	vectorData.push_back(Vec4(0.25f, -0.25f, 0, 1));
902	vectorData.push_back(Vec4(0.25f,  0.25f, 0, 1));
903	return vectorData;
904}
905
906// Tests rendering to a framebuffer without color attachments, checking that
907// the fragment shader is run even in the absence of color output. In this case
908// we render 4 point primitives and we make the fragment shader write to a
909// different pixel of an image via an imageStore command. For the single-sampled
910// configuration we use a 4x1 image to record the output and for the
911// multi-sampled case we use a 4x4 image to record all 16 samples produced by
912// 4-sample multi-sampling
913tcu::TestStatus testNoAtt (Context& context, const bool multisample)
914{
915	const VkPhysicalDeviceFeatures		features				= context.getDeviceFeatures();
916	if (!features.fragmentStoresAndAtomics)
917		throw tcu::NotSupportedError("fragmentStoresAndAtomics feature not supported");
918	if (!features.geometryShader && !features.tessellationShader) // Shader uses gl_PrimitiveID
919		throw tcu::NotSupportedError("geometryShader or tessellationShader feature not supported");
920	if (multisample && !features.sampleRateShading) // MS shader uses gl_SampleID
921		throw tcu::NotSupportedError("sampleRateShading feature not supported");
922
923	const DeviceInterface&				vk						= context.getDeviceInterface();
924	const VkDevice						device					= context.getDevice();
925	const VkQueue						queue					= context.getUniversalQueue();
926	const deUint32						queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
927	Allocator&							allocator				= context.getDefaultAllocator();
928	const IVec3							renderSize				(32, 32, 1);
929
930	Move<VkBuffer>						vertexBuffer;
931	MovePtr<Allocation>					vertexBufferAlloc;
932
933	const Unique<VkShaderModule>		vertexModule			(createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u));
934	const Unique<VkShaderModule>		fragmentModule			(createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u));
935
936	// Create image where we will record the writes. For single-sampled cases this is a 4x1 image
937	// and for multi-sampled cases this is a 4x<num_samples> image.
938	const deUint8						numSamples				= multisample ? 4 : 1;
939	const deUint8						imageWidth				= 4;
940	const deUint8						imageHeight				= numSamples;
941	const deUint8						imageDepth				= 1;
942	const deUint8						imageLayers				= 1;
943	const IVec3							imageDim				= IVec3(imageWidth, imageHeight, imageDepth);
944	const VkImageUsageFlags				imageUsage				= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
945	const Move<VkImage>					image					= makeImage(vk, device, VkImageViewCreateFlags(0), VK_IMAGE_TYPE_2D, COLOR_FORMAT, imageDim, imageLayers, imageUsage, false);
946	const VkImageSubresourceRange		imageSubresourceRange	= makeColorSubresourceRange(0u, imageLayers);
947	const MovePtr<Allocation>			imageAlloc				= bindImage(vk, device, allocator, *image, MemoryRequirement::Any);
948	const Move<VkImageView>				imageView				= makeImageView(vk, device, *image, VK_IMAGE_VIEW_TYPE_2D, COLOR_FORMAT, imageSubresourceRange);
949
950	// Create a buffer where we will copy the image for verification
951	const VkDeviceSize					colorBufferSize		= imageWidth * imageHeight * imageDepth * numSamples * tcu::getPixelSize(mapVkFormat(COLOR_FORMAT));
952	const Unique<VkBuffer>				colorBuffer			(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
953	const UniquePtr<Allocation>			colorBufferAlloc	(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
954
955	// Create pipeline descriptor set for the image
956	const Move<VkDescriptorSetLayout>	descriptorSetLayout		= DescriptorSetLayoutBuilder()
957		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT)
958		.build(vk, device);
959
960	const Move<VkDescriptorPool>		descriptorPool			= DescriptorPoolBuilder()
961		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1)
962		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1);
963
964	const Move<VkDescriptorSet>			descriptorSet			= makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
965	const VkDescriptorImageInfo			descriptorImageInfo		= makeDescriptorImageInfo(DE_NULL, *imageView, VK_IMAGE_LAYOUT_GENERAL);
966	DescriptorSetUpdateBuilder()
967		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
968		.update(vk, device);
969
970	const Unique<VkPipelineLayout>		pipelineLayout			(makePipelineLayout (vk, device, *descriptorSetLayout));
971	vector<SharedPtrVkPipeline>			pipeline;
972	const Unique<VkRenderPass>			renderPass				(makeRenderPassNoAtt (vk, device));
973	Move<VkFramebuffer>					framebuffer;
974
975	const Unique<VkCommandPool>			cmdPool					(createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
976	const Unique<VkCommandBuffer>		cmdBuffer				(makeCommandBuffer (vk, device, *cmdPool));
977
978	// create vertexBuffer
979	{
980		const vector<tcu::Vec4>	vertices			= genPointVertices();
981		const VkDeviceSize		vertexBufferSize	= sizeInBytes(vertices);
982
983		vertexBuffer		= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
984		vertexBufferAlloc	= bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
985		deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
986		flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
987	}
988
989	// Create render pass and pipeline
990	pipeline.push_back(makeSharedPtr(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
991		renderSize, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, false, multisample)));
992	framebuffer = makeFramebuffer(vk, device, *renderPass, 0, DE_NULL, renderSize.x(), renderSize.y());
993
994	// Record command buffer
995	beginCommandBuffer(vk, *cmdBuffer);
996	{
997		// shader image layout transition undefined -> general
998		{
999			const VkImageMemoryBarrier setImageLayoutBarrier = makeImageMemoryBarrier(
1000				0u, VK_ACCESS_SHADER_WRITE_BIT,
1001				VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
1002				*image, imageSubresourceRange);
1003
1004			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
1005				0, DE_NULL, 0, DE_NULL, 1, &setImageLayoutBarrier);
1006		}
1007
1008		// Render pass
1009		{
1010			const VkRect2D renderArea =
1011			{
1012				makeOffset2D(0, 0),
1013				makeExtent2D(renderSize.x(), renderSize.y()),
1014			};
1015			const VkRenderPassBeginInfo renderPassBeginInfo =
1016			{
1017				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// VkStructureType         sType;
1018				DE_NULL,									// const void*             pNext;
1019				*renderPass,								// VkRenderPass            renderPass;
1020				*framebuffer,								// VkFramebuffer           framebuffer;
1021				renderArea,									// VkRect2D                renderArea;
1022				0,											// uint32_t                clearValueCount;
1023				DE_NULL,									// const VkClearValue*     pClearValues;
1024			};
1025			const VkDeviceSize vertexBufferOffset = 0ull;
1026
1027			vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1028
1029			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipeline[0]);
1030			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1031			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1032			vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u);
1033
1034			vk.cmdEndRenderPass(*cmdBuffer);
1035		}
1036
1037		// copy image to host visible colorBuffer
1038		{
1039			const VkImageMemoryBarrier	imageBarriers[]		=
1040			{
1041				{
1042					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
1043					DE_NULL,									// const void*				pNext;
1044					VK_ACCESS_SHADER_WRITE_BIT,					// VkAccessFlags			srcAccessMask;
1045					VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags			dstAccessMask;
1046					VK_IMAGE_LAYOUT_GENERAL,					// VkImageLayout			oldLayout;
1047					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// VkImageLayout			newLayout;
1048					VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
1049					VK_QUEUE_FAMILY_IGNORED,					// deUint32					destQueueFamilyIndex;
1050					*image,										// VkImage					image;
1051					makeColorSubresourceRange(0, 1)				// VkImageSubresourceRange	subresourceRange;
1052				}
1053			};
1054
1055			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1056				0u, DE_NULL, 0u, DE_NULL, 1u, imageBarriers);
1057
1058			const VkBufferImageCopy		region				=
1059			{
1060				0ull,																// VkDeviceSize                bufferOffset;
1061				0u,																	// uint32_t                    bufferRowLength;
1062				0u,																	// uint32_t                    bufferImageHeight;
1063				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1),	// VkImageSubresourceLayers    imageSubresource;
1064				makeOffset3D(0, 0, 0),												// VkOffset3D                  imageOffset;
1065				makeExtent3D(IVec3(imageWidth, imageHeight, imageDepth)),			// VkExtent3D                  imageExtent;
1066			};
1067
1068			vk.cmdCopyImageToBuffer(*cmdBuffer, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
1069
1070			const VkBufferMemoryBarrier	bufferBarriers[]	=
1071			{
1072				{
1073					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType    sType;
1074					DE_NULL,									// const void*        pNext;
1075					VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags      srcAccessMask;
1076					VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags      dstAccessMask;
1077					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           srcQueueFamilyIndex;
1078					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           dstQueueFamilyIndex;
1079					*colorBuffer,								// VkBuffer           buffer;
1080					0ull,										// VkDeviceSize       offset;
1081					VK_WHOLE_SIZE,								// VkDeviceSize       size;
1082				},
1083			};
1084
1085			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1086				0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
1087		}
1088	} // beginCommandBuffer
1089
1090	VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1091	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1092
1093	// Verify results
1094	{
1095		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1096		const tcu::TextureFormat			format			= mapVkFormat(COLOR_FORMAT);
1097		tcu::TextureLevel					textureLevel	(format, imageWidth, imageHeight, imageDepth);
1098		const tcu::PixelBufferAccess		expectedImage	= getExpectedDataNoAtt(textureLevel);
1099		const tcu::ConstPixelBufferAccess	resultImage		(format, imageWidth, imageHeight, imageDepth, colorBufferAlloc->getHostPtr());
1100
1101		if (!tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT))
1102			return tcu::TestStatus::fail("Fail");
1103	}
1104
1105	return tcu::TestStatus::pass("Pass");
1106}
1107
1108std::string getShortImageViewTypeName (const VkImageViewType imageViewType)
1109{
1110	std::string	s	(getImageViewTypeName(imageViewType));
1111	return de::toLower(s.substr(19));
1112}
1113
1114std::string getSizeString (const CaseDef& caseDef)
1115{
1116	std::ostringstream	str;
1117
1118										str << caseDef.renderSize.x();
1119	if (caseDef.renderSize.y() > 1)		str << "x" << caseDef.renderSize.y();
1120	if (caseDef.renderSize.z() > 1)		str << "x" << caseDef.renderSize.z();
1121
1122										str << "_" << caseDef.attachmentSize.x();
1123
1124	if (caseDef.attachmentSize.y() > 1)	str << "x" << caseDef.attachmentSize.y();
1125	if (caseDef.attachmentSize.z() > 1)	str << "x" << caseDef.attachmentSize.z();
1126	if (caseDef.numLayers > 1)			str << "_" << caseDef.numLayers;
1127
1128	return str.str();
1129}
1130
1131std::string getTestCaseString (const CaseDef& caseDef)
1132{
1133	std::ostringstream str;
1134
1135	str << getShortImageViewTypeName (caseDef.imageType).c_str();
1136	str << "_";
1137	str << getSizeString(caseDef);
1138
1139	if (caseDef.multisample)
1140		str << "_ms";
1141
1142	return str.str();
1143}
1144
1145void addAttachmentTestCasesWithFunctions (tcu::TestCaseGroup* group)
1146{
1147
1148	// Add test cases for attachment strictly sizes larger than the framebuffer
1149	const CaseDef	caseDef[]	=
1150	{
1151		// Single-sample test cases
1152		{ VK_IMAGE_VIEW_TYPE_1D,			IVec3(32, 1, 1),	IVec3(64, 1, 1),	1,		false },
1153		{ VK_IMAGE_VIEW_TYPE_1D,			IVec3(32, 1, 1),	IVec3(48, 1, 1),	1,		false },
1154		{ VK_IMAGE_VIEW_TYPE_1D,			IVec3(32, 1, 1),	IVec3(39, 1, 1),	1,		false },
1155		{ VK_IMAGE_VIEW_TYPE_1D,			IVec3(19, 1, 1),	IVec3(32, 1, 1),	1,		false },
1156
1157		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		IVec3(32, 1, 1),	IVec3(64, 1, 1),	4,		false },
1158		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		IVec3(32, 1, 1),	IVec3(48, 1, 1),	4,		false },
1159		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		IVec3(32, 1, 1),	IVec3(39, 1, 1),	4,		false },
1160		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		IVec3(19, 1, 1),	IVec3(32, 1, 1),	4,		false },
1161
1162		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(64, 64, 1),	1,		false },
1163		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(48, 48, 1),	1,		false },
1164		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(39, 41, 1),	1,		false },
1165		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(19, 27, 1),	IVec3(32, 32, 1),	1,		false },
1166
1167		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(64, 64, 1),	4,		false },
1168		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(48, 48, 1),	4,		false },
1169		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(39, 41, 1),	4,		false },
1170		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(19, 27, 1),	IVec3(32, 32, 1),	4,		false },
1171
1172		{ VK_IMAGE_VIEW_TYPE_CUBE,			IVec3(32, 32, 1),	IVec3(64, 64, 1),	6,		false },
1173		{ VK_IMAGE_VIEW_TYPE_CUBE,			IVec3(32, 32, 1),	IVec3(48, 48, 1),	6,		false },
1174		{ VK_IMAGE_VIEW_TYPE_CUBE,			IVec3(32, 32, 1),	IVec3(39, 41, 1),	6,		false },
1175		{ VK_IMAGE_VIEW_TYPE_CUBE,			IVec3(19, 27, 1),	IVec3(32, 32, 1),	6,		false },
1176
1177		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	IVec3(32, 32, 1),	IVec3(64, 64, 1),	6*2,	false },
1178		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	IVec3(32, 32, 1),	IVec3(48, 48, 1),	6*2,	false },
1179		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	IVec3(32, 32, 1),	IVec3(39, 41, 1),	6*2,	false },
1180		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	IVec3(19, 27, 1),	IVec3(32, 32, 1),	6*2,	false },
1181
1182		// Multi-sample test cases
1183		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(64, 64, 1),	1,		true },
1184		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(48, 48, 1),	1,		true },
1185		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(32, 32, 1),	IVec3(39, 41, 1),	1,		true },
1186		{ VK_IMAGE_VIEW_TYPE_2D,			IVec3(19, 27, 1),	IVec3(32, 32, 1),	1,		true },
1187
1188		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(64, 64, 1),	4,		true },
1189		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(48, 48, 1),	4,		true },
1190		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(32, 32, 1),	IVec3(39, 41, 1),	4,		true },
1191		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec3(19, 27, 1),	IVec3(32, 32, 1),	4,		true },
1192	};
1193
1194	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(caseDef); ++sizeNdx)
1195		addFunctionCaseWithPrograms(group, getTestCaseString(caseDef[sizeNdx]).c_str(), "", initColorPrograms, test, caseDef[sizeNdx]);
1196
1197	// Add tests for the case where there are no color attachments but the
1198	// fragment shader writes to an image via imageStore().
1199	addFunctionCaseWithPrograms(group, "no_attachments", "", initImagePrograms, testNoAtt, false);
1200	addFunctionCaseWithPrograms(group, "no_attachments_ms", "", initImagePrograms, testNoAtt, true);
1201}
1202
1203} // anonymous ns
1204
1205tcu::TestCaseGroup* createFramebufferAttachmentTests (tcu::TestContext& testCtx)
1206{
1207	return createTestGroup(testCtx, "framebuffer_attachment", "Framebuffer attachment tests", addAttachmentTestCasesWithFunctions);
1208}
1209
1210} // pipeline
1211} // vkt
1212