Home | History | Annotate | Download | only in pipeline
      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 vktPipelineRenderToImageTests.cpp
     21  * \brief Render to image tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktPipelineRenderToImageTests.hpp"
     25 #include "vktPipelineMakeUtil.hpp"
     26 #include "vktTestCase.hpp"
     27 #include "vktTestCaseUtil.hpp"
     28 #include "vktPipelineVertexUtil.hpp"
     29 #include "vktTestGroupUtil.hpp"
     30 
     31 #include "vkMemUtil.hpp"
     32 #include "vkQueryUtil.hpp"
     33 #include "vkTypeUtil.hpp"
     34 #include "vkRefUtil.hpp"
     35 #include "vkBuilderUtil.hpp"
     36 #include "vkPrograms.hpp"
     37 #include "vkImageUtil.hpp"
     38 
     39 #include "tcuTextureUtil.hpp"
     40 #include "tcuImageCompare.hpp"
     41 #include "tcuTestLog.hpp"
     42 
     43 #include "deUniquePtr.hpp"
     44 #include "deSharedPtr.hpp"
     45 
     46 #include <string>
     47 #include <vector>
     48 #include <set>
     49 
     50 namespace vkt
     51 {
     52 namespace pipeline
     53 {
     54 namespace
     55 {
     56 using namespace vk;
     57 using de::UniquePtr;
     58 using de::MovePtr;
     59 using de::SharedPtr;
     60 using tcu::IVec3;
     61 using tcu::Vec4;
     62 using tcu::UVec4;
     63 using tcu::IVec2;
     64 using tcu::IVec4;
     65 using tcu::BVec4;
     66 using std::vector;
     67 
     68 typedef SharedPtr<Unique<VkImageView> >	SharedPtrVkImageView;
     69 typedef SharedPtr<Unique<VkPipeline> >	SharedPtrVkPipeline;
     70 
     71 enum Constants
     72 {
     73 	NUM_CUBE_FACES					= 6,
     74 	REFERENCE_COLOR_VALUE			= 125,
     75 	REFERENCE_STENCIL_VALUE			= 42,
     76 	MAX_SIZE						= -1,	//!< Should be queried at runtime and replaced with max possible value
     77 	MAX_VERIFICATION_REGION_SIZE	= 32,	//!<  Limit the checked area to a small size, especially for huge images
     78 	MAX_VERIFICATION_REGION_DEPTH	= 8,
     79 
     80 	MASK_W					= (1 | 0 | 0 | 0),
     81 	MASK_W_LAYERS			= (1 | 0 | 0 | 8),
     82 	MASK_WH					= (1 | 2 | 0 | 0),
     83 	MASK_WH_LAYERS			= (1 | 2 | 0 | 8),
     84 	MASK_WHD				= (1 | 2 | 4 | 0),
     85 };
     86 
     87 enum AllocationKind
     88 {
     89 	ALLOCATION_KIND_SUBALLOCATED = 0,
     90 	ALLOCATION_KIND_DEDICATED,
     91 };
     92 
     93 static const float	REFERENCE_DEPTH_VALUE	= 1.0f;
     94 static const Vec4	COLOR_TABLE[]			=
     95 {
     96 	Vec4(0.9f, 0.0f, 0.0f, 1.0f),
     97 	Vec4(0.6f, 1.0f, 0.0f, 1.0f),
     98 	Vec4(0.3f, 0.0f, 1.0f, 1.0f),
     99 	Vec4(0.1f, 1.0f, 1.0f, 1.0f),
    100 	Vec4(0.8f, 1.0f, 0.0f, 1.0f),
    101 	Vec4(0.5f, 0.0f, 1.0f, 1.0f),
    102 	Vec4(0.2f, 0.0f, 0.0f, 1.0f),
    103 	Vec4(1.0f, 1.0f, 0.0f, 1.0f),
    104 };
    105 
    106 struct CaseDef
    107 {
    108 	VkImageViewType	viewType;
    109 	IVec4			imageSizeHint;			//!< (w, h, d, layers), a component may have a symbolic value MAX_SIZE
    110 	VkFormat		colorFormat;
    111 	VkFormat		depthStencilFormat;		//! A depth/stencil format, or UNDEFINED if not used
    112 	AllocationKind	allocationKind;
    113 };
    114 
    115 template<typename T>
    116 inline SharedPtr<Unique<T> > makeSharedPtr (Move<T> move)
    117 {
    118 	return SharedPtr<Unique<T> >(new Unique<T>(move));
    119 }
    120 
    121 template<typename T>
    122 inline VkDeviceSize sizeInBytes (const vector<T>& vec)
    123 {
    124 	return vec.size() * sizeof(vec[0]);
    125 }
    126 
    127 inline bool isCube (const VkImageViewType viewType)
    128 {
    129 	return (viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
    130 }
    131 
    132 inline VkDeviceSize product (const IVec4& v)
    133 {
    134 	return ((static_cast<VkDeviceSize>(v.x()) * v.y()) * v.z()) * v.w();
    135 }
    136 
    137 template<typename T>
    138 inline T sum (const vector<T>& v)
    139 {
    140 	T total = static_cast<T>(0);
    141 	for (typename vector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
    142 		total += *it;
    143 	return total;
    144 }
    145 
    146 template <typename T, int Size>
    147 int findIndexOfMaxComponent (const tcu::Vector<T, Size>& vec)
    148 {
    149 	int index	= 0;
    150 	T	value	= vec[0];
    151 
    152 	for (int i = 1; i < Size; ++i)
    153 	{
    154 		if (vec[i] > value)
    155 		{
    156 			index	= i;
    157 			value	= vec[i];
    158 		}
    159 	}
    160 
    161 	return index;
    162 }
    163 
    164 inline int maxLayersOrDepth (const IVec4& size)
    165 {
    166 	// This is safe because 3D images must have layers (w) = 1
    167 	return deMax32(size.z(), size.w());
    168 }
    169 
    170 de::MovePtr<Allocation> bindBuffer (const InstanceInterface&	vki,
    171 									const DeviceInterface&		vkd,
    172 									const VkPhysicalDevice&		physDevice,
    173 									const VkDevice				device,
    174 									const VkBuffer&				buffer,
    175 									const MemoryRequirement		requirement,
    176 									Allocator&					allocator,
    177 									AllocationKind				allocationKind)
    178 {
    179 	switch (allocationKind)
    180 	{
    181 		case ALLOCATION_KIND_SUBALLOCATED:
    182 		{
    183 			return ::vkt::pipeline::bindBuffer(vkd, device, allocator, buffer, requirement);
    184 		}
    185 
    186 		case ALLOCATION_KIND_DEDICATED:
    187 		{
    188 			return bindBufferDedicated(vki, vkd, physDevice, device, buffer, requirement);
    189 		}
    190 
    191 		default:
    192 		{
    193 			TCU_THROW(InternalError, "Invalid allocation kind");
    194 		}
    195 	}
    196 }
    197 
    198 de::MovePtr<Allocation> bindImage (const InstanceInterface&		vki,
    199 								   const DeviceInterface&		vkd,
    200 								   const VkPhysicalDevice&		physDevice,
    201 								   const VkDevice				device,
    202 								   const VkImage&				image,
    203 								   const MemoryRequirement		requirement,
    204 								   Allocator&					allocator,
    205 								   AllocationKind				allocationKind)
    206 {
    207 	switch (allocationKind)
    208 	{
    209 		case ALLOCATION_KIND_SUBALLOCATED:
    210 		{
    211 			return ::vkt::pipeline::bindImage(vkd, device, allocator, image, requirement);
    212 		}
    213 
    214 		case ALLOCATION_KIND_DEDICATED:
    215 		{
    216 			return bindImageDedicated(vki, vkd, physDevice, device, image, requirement);
    217 		}
    218 
    219 		default:
    220 		{
    221 			TCU_THROW(InternalError, "Invalid allocation kind");
    222 		}
    223 	}
    224 }
    225 
    226 // This is very test specific, so be careful if you want to reuse this code.
    227 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
    228 									   const VkDevice				device,
    229 									   const VkPipeline				basePipeline,		// for derivatives
    230 									   const VkPipelineLayout		pipelineLayout,
    231 									   const VkRenderPass			renderPass,
    232 									   const VkShaderModule			vertexModule,
    233 									   const VkShaderModule			fragmentModule,
    234 									   const IVec2&					renderSize,
    235 									   const VkPrimitiveTopology	topology,
    236 									   const deUint32				subpass,
    237 									   const bool					useDepth,
    238 									   const bool					useStencil)
    239 {
    240 	const VkVertexInputBindingDescription vertexInputBindingDescription =
    241 	{
    242 		0u,								// uint32_t				binding;
    243 		sizeof(Vertex4RGBA),			// uint32_t				stride;
    244 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
    245 	};
    246 
    247 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
    248 	{
    249 		{
    250 			0u,								// uint32_t			location;
    251 			0u,								// uint32_t			binding;
    252 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat			format;
    253 			0u,								// uint32_t			offset;
    254 		},
    255 		{
    256 			1u,								// uint32_t			location;
    257 			0u,								// uint32_t			binding;
    258 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat			format;
    259 			sizeof(Vec4),					// uint32_t			offset;
    260 		}
    261 	};
    262 
    263 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
    264 	{
    265 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType							sType;
    266 		DE_NULL,													// const void*								pNext;
    267 		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags	flags;
    268 		1u,															// uint32_t									vertexBindingDescriptionCount;
    269 		&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
    270 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),		// uint32_t									vertexAttributeDescriptionCount;
    271 		vertexInputAttributeDescriptions,							// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
    272 	};
    273 
    274 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
    275 	{
    276 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType;
    277 		DE_NULL,														// const void*								pNext;
    278 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags	flags;
    279 		topology,														// VkPrimitiveTopology						topology;
    280 		VK_FALSE,														// VkBool32									primitiveRestartEnable;
    281 	};
    282 
    283 	const VkViewport viewport = makeViewport(
    284 		0.0f, 0.0f,
    285 		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
    286 		0.0f, 1.0f);
    287 
    288 	const VkRect2D scissor =
    289 	{
    290 		makeOffset2D(0, 0),
    291 		makeExtent2D(renderSize.x(), renderSize.y()),
    292 	};
    293 
    294 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
    295 	{
    296 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType						sType;
    297 		DE_NULL,												// const void*							pNext;
    298 		(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags	flags;
    299 		1u,														// uint32_t								viewportCount;
    300 		&viewport,												// const VkViewport*					pViewports;
    301 		1u,														// uint32_t								scissorCount;
    302 		&scissor,												// const VkRect2D*						pScissors;
    303 	};
    304 
    305 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
    306 	{
    307 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	// VkStructureType							sType;
    308 		DE_NULL,													// const void*								pNext;
    309 		(VkPipelineRasterizationStateCreateFlags)0,					// VkPipelineRasterizationStateCreateFlags	flags;
    310 		VK_FALSE,													// VkBool32									depthClampEnable;
    311 		VK_FALSE,													// VkBool32									rasterizerDiscardEnable;
    312 		VK_POLYGON_MODE_FILL,										// VkPolygonMode							polygonMode;
    313 		VK_CULL_MODE_NONE,											// VkCullModeFlags							cullMode;
    314 		VK_FRONT_FACE_COUNTER_CLOCKWISE,							// VkFrontFace								frontFace;
    315 		VK_FALSE,													// VkBool32									depthBiasEnable;
    316 		0.0f,														// float									depthBiasConstantFactor;
    317 		0.0f,														// float									depthBiasClamp;
    318 		0.0f,														// float									depthBiasSlopeFactor;
    319 		1.0f,														// float									lineWidth;
    320 	};
    321 
    322 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
    323 	{
    324 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
    325 		DE_NULL,													// const void*								pNext;
    326 		(VkPipelineMultisampleStateCreateFlags)0,					// VkPipelineMultisampleStateCreateFlags	flags;
    327 		VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits					rasterizationSamples;
    328 		VK_FALSE,													// VkBool32									sampleShadingEnable;
    329 		0.0f,														// float									minSampleShading;
    330 		DE_NULL,													// const VkSampleMask*						pSampleMask;
    331 		VK_FALSE,													// VkBool32									alphaToCoverageEnable;
    332 		VK_FALSE													// VkBool32									alphaToOneEnable;
    333 	};
    334 
    335 	const VkStencilOpState stencilOpState = makeStencilOpState(
    336 		VK_STENCIL_OP_KEEP,									// stencil fail
    337 		VK_STENCIL_OP_ZERO,									// depth & stencil pass
    338 		VK_STENCIL_OP_KEEP,									// depth only fail
    339 		VK_COMPARE_OP_EQUAL,								// compare op
    340 		~0u,												// compare mask
    341 		~0u,												// write mask
    342 		static_cast<deUint32>(REFERENCE_STENCIL_VALUE));	// reference
    343 
    344 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
    345 	{
    346 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
    347 		DE_NULL,													// const void*								pNext;
    348 		(VkPipelineDepthStencilStateCreateFlags)0,					// VkPipelineDepthStencilStateCreateFlags	flags;
    349 		useDepth,													// VkBool32									depthTestEnable;
    350 		VK_FALSE,													// VkBool32									depthWriteEnable;
    351 		VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
    352 		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
    353 		useStencil,													// VkBool32									stencilTestEnable;
    354 		stencilOpState,												// VkStencilOpState							front;
    355 		stencilOpState,												// VkStencilOpState							back;
    356 		0.0f,														// float									minDepthBounds;
    357 		1.0f,														// float									maxDepthBounds;
    358 	};
    359 
    360 	const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    361 	// Number of blend attachments must equal the number of color attachments during any subpass.
    362 	const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
    363 	{
    364 		VK_FALSE,				// VkBool32					blendEnable;
    365 		VK_BLEND_FACTOR_ONE,	// VkBlendFactor			srcColorBlendFactor;
    366 		VK_BLEND_FACTOR_ZERO,	// VkBlendFactor			dstColorBlendFactor;
    367 		VK_BLEND_OP_ADD,		// VkBlendOp				colorBlendOp;
    368 		VK_BLEND_FACTOR_ONE,	// VkBlendFactor			srcAlphaBlendFactor;
    369 		VK_BLEND_FACTOR_ZERO,	// VkBlendFactor			dstAlphaBlendFactor;
    370 		VK_BLEND_OP_ADD,		// VkBlendOp				alphaBlendOp;
    371 		colorComponentsAll,		// VkColorComponentFlags	colorWriteMask;
    372 	};
    373 
    374 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
    375 	{
    376 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
    377 		DE_NULL,													// const void*									pNext;
    378 		(VkPipelineColorBlendStateCreateFlags)0,					// VkPipelineColorBlendStateCreateFlags			flags;
    379 		VK_FALSE,													// VkBool32										logicOpEnable;
    380 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
    381 		1u,															// deUint32										attachmentCount;
    382 		&pipelineColorBlendAttachmentState,							// const VkPipelineColorBlendAttachmentState*	pAttachments;
    383 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConstants[4];
    384 	};
    385 
    386 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
    387 	{
    388 		{
    389 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
    390 			DE_NULL,												// const void*							pNext;
    391 			(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
    392 			VK_SHADER_STAGE_VERTEX_BIT,								// VkShaderStageFlagBits				stage;
    393 			vertexModule,											// VkShaderModule						module;
    394 			"main",													// const char*							pName;
    395 			DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
    396 		},
    397 		{
    398 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
    399 			DE_NULL,												// const void*							pNext;
    400 			(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
    401 			VK_SHADER_STAGE_FRAGMENT_BIT,							// VkShaderStageFlagBits				stage;
    402 			fragmentModule,											// VkShaderModule						module;
    403 			"main",													// const char*							pName;
    404 			DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
    405 		}
    406 	};
    407 
    408 	const VkPipelineCreateFlags			flags = (basePipeline == DE_NULL ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
    409 																		 : VK_PIPELINE_CREATE_DERIVATIVE_BIT);
    410 
    411 	const VkGraphicsPipelineCreateInfo	graphicsPipelineInfo =
    412 	{
    413 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
    414 		DE_NULL,											// const void*										pNext;
    415 		flags,												// VkPipelineCreateFlags							flags;
    416 		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
    417 		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
    418 		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
    419 		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
    420 		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
    421 		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
    422 		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
    423 		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
    424 		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
    425 		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
    426 		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
    427 		pipelineLayout,										// VkPipelineLayout									layout;
    428 		renderPass,											// VkRenderPass										renderPass;
    429 		subpass,											// deUint32											subpass;
    430 		basePipeline,										// VkPipeline										basePipelineHandle;
    431 		-1,													// deInt32											basePipelineIndex;
    432 	};
    433 
    434 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
    435 }
    436 
    437 //! Make a render pass with one subpass per color attachment and depth/stencil attachment (if used).
    438 Move<VkRenderPass> makeRenderPass (const DeviceInterface&		vk,
    439 								   const VkDevice				device,
    440 								   const VkFormat				colorFormat,
    441 								   const VkFormat				depthStencilFormat,
    442 								   const deUint32				numLayers,
    443 								   const VkImageLayout			initialColorImageLayout			= VK_IMAGE_LAYOUT_UNDEFINED,
    444 								   const VkImageLayout			initialDepthStencilImageLayout	= VK_IMAGE_LAYOUT_UNDEFINED)
    445 {
    446 	const VkAttachmentDescription colorAttachmentDescription =
    447 	{
    448 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    449 		colorFormat,										// VkFormat							format;
    450 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    451 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    452 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
    453 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
    454 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    455 		initialColorImageLayout,							// VkImageLayout					initialLayout;
    456 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
    457 	};
    458 	vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
    459 
    460 	const VkAttachmentDescription depthStencilAttachmentDescription =
    461 	{
    462 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    463 		depthStencilFormat,									// VkFormat							format;
    464 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    465 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    466 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				storeOp;
    467 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				stencilLoadOp;
    468 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    469 		initialDepthStencilImageLayout,						// VkImageLayout					initialLayout;
    470 		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout					finalLayout;
    471 	};
    472 
    473 	if (depthStencilFormat != VK_FORMAT_UNDEFINED)
    474 		attachmentDescriptions.insert(attachmentDescriptions.end(), numLayers, depthStencilAttachmentDescription);
    475 
    476 	// Create a subpass for each attachment (each attachement is a layer of an arrayed image).
    477 	vector<VkAttachmentReference>	colorAttachmentReferences		(numLayers);
    478 	vector<VkAttachmentReference>	depthStencilAttachmentReferences(numLayers);
    479 	vector<VkSubpassDescription>	subpasses;
    480 
    481 	// Ordering here must match the framebuffer attachments
    482 	for (deUint32 i = 0; i < numLayers; ++i)
    483 	{
    484 		const VkAttachmentReference attachmentRef =
    485 		{
    486 			i,													// deUint32			attachment;
    487 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
    488 		};
    489 		const VkAttachmentReference depthStencilAttachmentRef =
    490 		{
    491 			i + numLayers,										// deUint32			attachment;
    492 			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL	// VkImageLayout	layout;
    493 		};
    494 
    495 		colorAttachmentReferences[i]		= attachmentRef;
    496 		depthStencilAttachmentReferences[i]	= depthStencilAttachmentRef;
    497 
    498 		const VkAttachmentReference*	pDepthStencilAttachment	= (depthStencilFormat != VK_FORMAT_UNDEFINED ? &depthStencilAttachmentReferences[i] : DE_NULL);
    499 		const VkSubpassDescription		subpassDescription		=
    500 		{
    501 			(VkSubpassDescriptionFlags)0,					// VkSubpassDescriptionFlags		flags;
    502 			VK_PIPELINE_BIND_POINT_GRAPHICS,				// VkPipelineBindPoint				pipelineBindPoint;
    503 			0u,												// deUint32							inputAttachmentCount;
    504 			DE_NULL,										// const VkAttachmentReference*		pInputAttachments;
    505 			1u,												// deUint32							colorAttachmentCount;
    506 			&colorAttachmentReferences[i],					// const VkAttachmentReference*		pColorAttachments;
    507 			DE_NULL,										// const VkAttachmentReference*		pResolveAttachments;
    508 			pDepthStencilAttachment,						// const VkAttachmentReference*		pDepthStencilAttachment;
    509 			0u,												// deUint32							preserveAttachmentCount;
    510 			DE_NULL											// const deUint32*					pPreserveAttachments;
    511 		};
    512 		subpasses.push_back(subpassDescription);
    513 	}
    514 
    515 	const VkRenderPassCreateInfo renderPassInfo =
    516 	{
    517 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType					sType;
    518 		DE_NULL,												// const void*						pNext;
    519 		(VkRenderPassCreateFlags)0,								// VkRenderPassCreateFlags			flags;
    520 		static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32							attachmentCount;
    521 		&attachmentDescriptions[0],								// const VkAttachmentDescription*	pAttachments;
    522 		static_cast<deUint32>(subpasses.size()),				// deUint32							subpassCount;
    523 		&subpasses[0],											// const VkSubpassDescription*		pSubpasses;
    524 		0u,														// deUint32							dependencyCount;
    525 		DE_NULL													// const VkSubpassDependency*		pDependencies;
    526 	};
    527 
    528 	return createRenderPass(vk, device, &renderPassInfo);
    529 }
    530 
    531 Move<VkImage> makeImage (const DeviceInterface&		vk,
    532 						 const VkDevice				device,
    533 						 VkImageCreateFlags			flags,
    534 						 VkImageType				imageType,
    535 						 const VkFormat				format,
    536 						 const IVec3&				size,
    537 						 const deUint32				numMipLevels,
    538 						 const deUint32				numLayers,
    539 						 const VkImageUsageFlags	usage)
    540 {
    541 	const VkImageCreateInfo imageParams =
    542 	{
    543 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	// VkStructureType			sType;
    544 		DE_NULL,								// const void*				pNext;
    545 		flags,									// VkImageCreateFlags		flags;
    546 		imageType,								// VkImageType				imageType;
    547 		format,									// VkFormat					format;
    548 		makeExtent3D(size),						// VkExtent3D				extent;
    549 		numMipLevels,							// deUint32					mipLevels;
    550 		numLayers,								// deUint32					arrayLayers;
    551 		VK_SAMPLE_COUNT_1_BIT,					// VkSampleCountFlagBits	samples;
    552 		VK_IMAGE_TILING_OPTIMAL,				// VkImageTiling			tiling;
    553 		usage,									// VkImageUsageFlags		usage;
    554 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode			sharingMode;
    555 		0u,										// deUint32					queueFamilyIndexCount;
    556 		DE_NULL,								// const deUint32*			pQueueFamilyIndices;
    557 		VK_IMAGE_LAYOUT_UNDEFINED,				// VkImageLayout			initialLayout;
    558 	};
    559 	return createImage(vk, device, &imageParams);
    560 }
    561 
    562 inline Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize bufferSize, const VkBufferUsageFlags usage)
    563 {
    564 	const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, usage);
    565 	return createBuffer(vk, device, &bufferCreateInfo);
    566 }
    567 
    568 inline VkImageSubresourceRange makeColorSubresourceRange (const int baseArrayLayer, const int layerCount)
    569 {
    570 	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount));
    571 }
    572 
    573 //! Get a reference clear value based on color format.
    574 VkClearValue getClearValue (const VkFormat format)
    575 {
    576 	if (isUintFormat(format) || isIntFormat(format))
    577 		return makeClearValueColorU32(REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE, REFERENCE_COLOR_VALUE);
    578 	else
    579 		return makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f);
    580 }
    581 
    582 std::string getColorFormatStr (const int numComponents, const bool isUint, const bool isSint)
    583 {
    584 	std::ostringstream str;
    585 	if (numComponents == 1)
    586 		str << (isUint ? "uint" : isSint ? "int" : "float");
    587 	else
    588 		str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
    589 
    590 	return str.str();
    591 }
    592 
    593 //! A half-viewport quad. Use with TRIANGLE_STRIP topology.
    594 vector<Vertex4RGBA> genFullQuadVertices (const int subpassCount)
    595 {
    596 	vector<Vertex4RGBA>	vectorData;
    597 	for (int subpassNdx = 0; subpassNdx < subpassCount; ++subpassNdx)
    598 	{
    599 		Vertex4RGBA data =
    600 		{
    601 			Vec4(0.0f, -1.0f, 0.0f, 1.0f),
    602 			COLOR_TABLE[subpassNdx % DE_LENGTH_OF_ARRAY(COLOR_TABLE)],
    603 		};
    604 		vectorData.push_back(data);
    605 		data.position	= Vec4(0.0f,  1.0f, 0.0f, 1.0f);
    606 		vectorData.push_back(data);
    607 		data.position	= Vec4(1.0f, -1.0f, 0.0f, 1.0f);
    608 		vectorData.push_back(data);
    609 		data.position	= Vec4(1.0f,  1.0f, 0.0f, 1.0f);
    610 		vectorData.push_back(data);
    611 	}
    612 	return vectorData;
    613 }
    614 
    615 VkImageType getImageType (const VkImageViewType viewType)
    616 {
    617 	switch (viewType)
    618 	{
    619 		case VK_IMAGE_VIEW_TYPE_1D:
    620 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
    621 			return VK_IMAGE_TYPE_1D;
    622 
    623 		case VK_IMAGE_VIEW_TYPE_2D:
    624 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
    625 		case VK_IMAGE_VIEW_TYPE_CUBE:
    626 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
    627 			return VK_IMAGE_TYPE_2D;
    628 
    629 		case VK_IMAGE_VIEW_TYPE_3D:
    630 			return VK_IMAGE_TYPE_3D;
    631 
    632 		default:
    633 			DE_ASSERT(0);
    634 			return VK_IMAGE_TYPE_LAST;
    635 	}
    636 }
    637 
    638 //! ImageViewType for accessing a single layer/slice of an image
    639 VkImageViewType getImageViewSliceType (const VkImageViewType viewType)
    640 {
    641 	switch (viewType)
    642 	{
    643 		case VK_IMAGE_VIEW_TYPE_1D:
    644 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
    645 			return VK_IMAGE_VIEW_TYPE_1D;
    646 
    647 		case VK_IMAGE_VIEW_TYPE_2D:
    648 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
    649 		case VK_IMAGE_VIEW_TYPE_CUBE:
    650 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
    651 		case VK_IMAGE_VIEW_TYPE_3D:
    652 			return VK_IMAGE_VIEW_TYPE_2D;
    653 
    654 		default:
    655 			DE_ASSERT(0);
    656 			return VK_IMAGE_VIEW_TYPE_LAST;
    657 	}
    658 }
    659 
    660 VkImageCreateFlags getImageCreateFlags (const VkImageViewType viewType)
    661 {
    662 	VkImageCreateFlags	flags	= (VkImageCreateFlags)0;
    663 
    664 	if (viewType == VK_IMAGE_VIEW_TYPE_3D)	flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR;
    665 	if (isCube(viewType))					flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
    666 
    667 	return flags;
    668 }
    669 
    670 void generateExpectedImage (const tcu::PixelBufferAccess& outputImage, const IVec2& renderSize, const int colorDepthOffset)
    671 {
    672 	const tcu::TextureChannelClass	channelClass	= tcu::getTextureChannelClass(outputImage.getFormat().type);
    673 	const bool						isInt			= (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER);
    674 	const VkClearValue				clearValue		= getClearValue(mapTextureFormat(outputImage.getFormat()));
    675 
    676 	if (isInt)
    677 		tcu::clear(outputImage, IVec4(clearValue.color.int32));
    678 	else
    679 		tcu::clear(outputImage, Vec4(clearValue.color.float32));
    680 
    681 	for (int z = 0; z < outputImage.getDepth(); ++z)
    682 	{
    683 		const Vec4& setColor	= COLOR_TABLE[(z + colorDepthOffset) % DE_LENGTH_OF_ARRAY(COLOR_TABLE)];
    684 		const IVec4 setColorInt	= (static_cast<float>(REFERENCE_COLOR_VALUE) * setColor).cast<deInt32>();
    685 
    686 		for (int y = 0;					y < renderSize.y(); ++y)
    687 		for (int x = renderSize.x()/2;	x < renderSize.x(); ++x)
    688 		{
    689 			if (isInt)
    690 				outputImage.setPixel(setColorInt, x, y, z);
    691 			else
    692 				outputImage.setPixel(setColor, x, y, z);
    693 		}
    694 	}
    695 }
    696 
    697 VkDeviceSize getMaxDeviceHeapSize (const InstanceInterface& vki, const VkPhysicalDevice physDevice)
    698 {
    699 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, physDevice);
    700 	VkDeviceSize							memorySize			= 0;
    701 
    702 	for (deUint32 heapNdx = 0; heapNdx < memoryProperties.memoryHeapCount; ++heapNdx)
    703 	{
    704 		if ((memoryProperties.memoryHeaps[heapNdx].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
    705 			memorySize = std::max(memorySize, memoryProperties.memoryHeaps[heapNdx].size);
    706 	}
    707 
    708 	return memorySize;
    709 }
    710 
    711 //! Get a smaller image size. Returns a vector of zeroes, if it can't reduce more.
    712 IVec4 getReducedImageSize (const CaseDef& caseDef, IVec4 size)
    713 {
    714 	const int maxIndex		= findIndexOfMaxComponent(size);
    715 	const int reducedSize	= size[maxIndex] >> 1;
    716 
    717 	switch (caseDef.viewType)
    718 	{
    719 		case VK_IMAGE_VIEW_TYPE_CUBE:
    720 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
    721 			if (maxIndex < 2)
    722 				size.x() = size.y() = reducedSize;
    723 			else if (maxIndex == 3 && reducedSize >= NUM_CUBE_FACES)
    724 				size.w() = NUM_CUBE_FACES * (reducedSize / NUM_CUBE_FACES); // round down to a multiple of 6
    725 			else
    726 				size = IVec4(0);
    727 			break;
    728 
    729 		default:
    730 			size[maxIndex] = reducedSize;
    731 			break;
    732 	}
    733 
    734 	if (reducedSize == 0)
    735 		size = IVec4(0);
    736 
    737 	return size;
    738 }
    739 
    740 bool isDepthStencilFormatSupported (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format)
    741 {
    742 	const VkFormatProperties properties = getPhysicalDeviceFormatProperties(vki, physDevice, format);
    743 	return (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
    744 }
    745 
    746 IVec4 getMaxImageSize (const VkPhysicalDeviceLimits& limits, const VkImageViewType viewType, const IVec4& sizeHint, const bool useDepthStencil)
    747 {
    748 	// If we use a layered D/S together with a 3D image, we have to use the smallest common limit
    749 	const int maxDepth = (useDepthStencil ? deMin32(static_cast<int>(limits.maxImageArrayLayers), static_cast<int>(limits.maxImageDimension3D))
    750 										  : static_cast<int>(limits.maxImageDimension3D));
    751 
    752 	// Images have to respect framebuffer limits and image limits (the framebuffer is not layered in this case)
    753 	IVec4 size = IVec4(
    754 		sizeHint.x() != MAX_SIZE ? sizeHint.x() : static_cast<int>(limits.maxFramebufferWidth),
    755 		sizeHint.y() != MAX_SIZE ? sizeHint.y() : static_cast<int>(limits.maxFramebufferHeight),
    756 		sizeHint.z() != MAX_SIZE ? sizeHint.z() : maxDepth,
    757 		sizeHint.w() != MAX_SIZE ? sizeHint.w() : static_cast<int>(limits.maxImageArrayLayers));
    758 
    759 	switch (viewType)
    760 	{
    761 		case VK_IMAGE_VIEW_TYPE_1D:
    762 		case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
    763 			size.x() = deMin32(size.x(), limits.maxImageDimension1D);
    764 			break;
    765 
    766 		case VK_IMAGE_VIEW_TYPE_2D:
    767 		case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
    768 			size.x() = deMin32(size.x(), limits.maxImageDimension2D);
    769 			size.y() = deMin32(size.y(), limits.maxImageDimension2D);
    770 			break;
    771 
    772 		case VK_IMAGE_VIEW_TYPE_3D:
    773 			size.x() = deMin32(size.x(), limits.maxImageDimension3D);
    774 			size.y() = deMin32(size.y(), limits.maxImageDimension3D);
    775 			break;
    776 
    777 		case VK_IMAGE_VIEW_TYPE_CUBE:
    778 		case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
    779 			size.x() = size.y() = deMin32(size.x(), limits.maxImageDimensionCube);
    780 			size.w() = NUM_CUBE_FACES * (size.w() / NUM_CUBE_FACES);	// round down to 6 faces
    781 			break;
    782 
    783 		default:
    784 			DE_ASSERT(0);
    785 			return IVec4();
    786 	}
    787 
    788 	return size;
    789 }
    790 
    791 VkImageAspectFlags getFormatAspectFlags (const VkFormat format)
    792 {
    793 	if (format == VK_FORMAT_UNDEFINED)
    794 		return 0;
    795 
    796 	const tcu::TextureFormat::ChannelOrder	order	= mapVkFormat(format).order;
    797 
    798 	switch (order)
    799 	{
    800 		case tcu::TextureFormat::DS:	return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
    801 		case tcu::TextureFormat::D:		return VK_IMAGE_ASPECT_DEPTH_BIT;
    802 		case tcu::TextureFormat::S:		return VK_IMAGE_ASPECT_STENCIL_BIT;
    803 		default:						return VK_IMAGE_ASPECT_COLOR_BIT;
    804 	}
    805 }
    806 
    807 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
    808 {
    809 	const int	numComponents	= getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
    810 	const bool	isUint			= isUintFormat(caseDef.colorFormat);
    811 	const bool	isSint			= isIntFormat(caseDef.colorFormat);
    812 
    813 	// Vertex shader
    814 	{
    815 		std::ostringstream src;
    816 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    817 			<< "\n"
    818 			<< "layout(location = 0) in  vec4 in_position;\n"
    819 			<< "layout(location = 1) in  vec4 in_color;\n"
    820 			<< "layout(location = 0) out vec4 out_color;\n"
    821 			<< "\n"
    822 			<< "out gl_PerVertex {\n"
    823 			<< "	vec4 gl_Position;\n"
    824 			<< "};\n"
    825 			<< "\n"
    826 			<< "void main(void)\n"
    827 			<< "{\n"
    828 			<< "	gl_Position	= in_position;\n"
    829 			<< "	out_color	= in_color;\n"
    830 			<< "}\n";
    831 
    832 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    833 	}
    834 
    835 	// Fragment shader
    836 	{
    837 		std::ostringstream colorValue;
    838 		colorValue << REFERENCE_COLOR_VALUE;
    839 		const std::string colorFormat	= getColorFormatStr(numComponents, isUint, isSint);
    840 		const std::string colorInteger	= (isUint || isSint ? " * "+colorFormat+"("+colorValue.str()+")" :"");
    841 
    842 		std::ostringstream src;
    843 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    844 			<< "\n"
    845 			<< "layout(location = 0) in  vec4 in_color;\n"
    846 			<< "layout(location = 0) out " << colorFormat << " o_color;\n"
    847 			<< "\n"
    848 			<< "void main(void)\n"
    849 			<< "{\n"
    850 			<< "    o_color = " << colorFormat << "("
    851 			<< (numComponents == 1 ? "in_color.r"   :
    852 				numComponents == 2 ? "in_color.rg"  :
    853 				numComponents == 3 ? "in_color.rgb" : "in_color")
    854 			<< colorInteger
    855 			<< ");\n"
    856 			<< "}\n";
    857 
    858 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    859 	}
    860 }
    861 
    862 //! See testAttachmentSize() description
    863 tcu::TestStatus testWithSizeReduction (Context& context, const CaseDef& caseDef, const int sizeReductionIndex)
    864 {
    865 	const DeviceInterface&			vk					= context.getDeviceInterface();
    866 	const InstanceInterface&		vki					= context.getInstanceInterface();
    867 	const VkDevice					device				= context.getDevice();
    868 	const VkPhysicalDevice			physDevice			= context.getPhysicalDevice();
    869 	const VkQueue					queue				= context.getUniversalQueue();
    870 	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
    871 	Allocator&						allocator			= context.getDefaultAllocator();
    872 
    873 	// The memory might be too small to allocate a largest possible attachment, so try to account for that.
    874 	const bool						useDepthStencil		= (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
    875 	const VkDeviceSize				deviceMemoryBudget	= getMaxDeviceHeapSize(vki, physDevice) >> 2;
    876 	IVec4							imageSize			= getMaxImageSize(context.getDeviceProperties().limits, caseDef.viewType, caseDef.imageSizeHint, useDepthStencil);
    877 
    878 	// Keep reducing the size, if needed
    879 	for (int i = 0; i < sizeReductionIndex; ++i)
    880 	{
    881 		imageSize = getReducedImageSize(caseDef, imageSize);
    882 
    883 		if (imageSize == IVec4())
    884 			return tcu::TestStatus::fail("Couldn't create an image with required size");
    885 	}
    886 
    887 	context.getTestContext().getLog()
    888 		<< tcu::TestLog::Message << "Using an image with size (width, height, depth, layers) = " << imageSize << tcu::TestLog::EndMessage;
    889 
    890 	// "Slices" is either the depth of a 3D image, or the number of layers of an arrayed image
    891 	const deInt32					numSlices			= maxLayersOrDepth(imageSize);
    892 	const VkDeviceSize				colorSize			= product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
    893 	const VkDeviceSize				depthStencilSize	= (useDepthStencil ? product(imageSize) * tcu::getPixelSize(mapVkFormat(caseDef.depthStencilFormat)) : 0ull);
    894 
    895 	if (useDepthStencil && !isDepthStencilFormatSupported(vki, physDevice, caseDef.depthStencilFormat))
    896 		TCU_THROW(NotSupportedError, "Unsupported depth/stencil format");
    897 
    898 	if (colorSize + depthStencilSize > deviceMemoryBudget)
    899 		throw OutOfMemoryError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Image size exceeds test's image memory budget");
    900 
    901 	// Determine the verification bounds. The checked region will be in the center of the rendered image
    902 	const IVec4	checkSize	= tcu::min(imageSize, IVec4(MAX_VERIFICATION_REGION_SIZE,
    903 														MAX_VERIFICATION_REGION_SIZE,
    904 														MAX_VERIFICATION_REGION_DEPTH,
    905 														MAX_VERIFICATION_REGION_DEPTH));
    906 	const IVec4	checkOffset	= (imageSize - checkSize) / 2;
    907 
    908 	// Only make enough space for the check region
    909 	const VkDeviceSize				colorBufferSize		= product(checkSize) * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
    910 	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
    911 	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
    912 
    913 	{
    914 		deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
    915 		flushMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
    916 	}
    917 
    918 	const Unique<VkShaderModule>	vertexModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("vert"), 0u));
    919 	const Unique<VkShaderModule>	fragmentModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("frag"), 0u));
    920 	const Unique<VkRenderPass>		renderPass		(makeRenderPass				(vk, device, caseDef.colorFormat, caseDef.depthStencilFormat, static_cast<deUint32>(numSlices),
    921 																				 (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
    922 																															 : VK_IMAGE_LAYOUT_UNDEFINED));
    923 	const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout			(vk, device));
    924 	vector<SharedPtrVkPipeline>		pipelines;
    925 
    926 	Move<VkImage>					colorImage;
    927 	MovePtr<Allocation>				colorImageAlloc;
    928 	vector<SharedPtrVkImageView>	colorAttachments;
    929 	Move<VkImage>					depthStencilImage;
    930 	MovePtr<Allocation>				depthStencilImageAlloc;
    931 	vector<SharedPtrVkImageView>	depthStencilAttachments;
    932 	vector<VkImageView>				attachmentHandles;			// all attachments (color and d/s)
    933 	Move<VkBuffer>					vertexBuffer;
    934 	MovePtr<Allocation>				vertexBufferAlloc;
    935 	Move<VkFramebuffer>				framebuffer;
    936 
    937 	// Create a color image
    938 	{
    939 		const VkImageUsageFlags	imageUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
    940 
    941 		colorImage		= makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat,
    942 									imageSize.swizzle(0, 1, 2), 1u, imageSize.w(), imageUsage);
    943 		colorImageAlloc	= bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
    944 	}
    945 
    946 	// Create a depth/stencil image (always a 2D image, optionally layered)
    947 	if (useDepthStencil)
    948 	{
    949 		const VkImageUsageFlags	imageUsage	= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
    950 
    951 		depthStencilImage		= makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
    952 											IVec3(imageSize.x(), imageSize.y(), 1), 1u, numSlices, imageUsage);
    953 		depthStencilImageAlloc	= bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
    954 	}
    955 
    956 	// Create a vertex buffer
    957 	{
    958 		const vector<Vertex4RGBA>	vertices			= genFullQuadVertices(numSlices);
    959 		const VkDeviceSize			vertexBufferSize	= sizeInBytes(vertices);
    960 
    961 		vertexBuffer		= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
    962 		vertexBufferAlloc	= bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind);
    963 
    964 		deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
    965 		flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
    966 	}
    967 
    968 	// Prepare color image upfront for rendering to individual slices.  3D slices aren't separate subresources, so they shouldn't be transitioned
    969 	// during each subpass like array layers.
    970 	if (caseDef.viewType == VK_IMAGE_VIEW_TYPE_3D)
    971 	{
    972 		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
    973 		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
    974 
    975 		beginCommandBuffer(vk, *cmdBuffer);
    976 
    977 		const VkImageMemoryBarrier	imageBarrier	=
    978 		{
    979 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// VkStructureType            sType;
    980 			DE_NULL,											// const void*                pNext;
    981 			(VkAccessFlags)0,									// VkAccessFlags              srcAccessMask;
    982 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,				// VkAccessFlags              dstAccessMask;
    983 			VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout              oldLayout;
    984 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout              newLayout;
    985 			VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   srcQueueFamilyIndex;
    986 			VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   dstQueueFamilyIndex;
    987 			*colorImage,										// VkImage                    image;
    988 			{													// VkImageSubresourceRange    subresourceRange;
    989 				VK_IMAGE_ASPECT_COLOR_BIT,							// VkImageAspectFlags    aspectMask;
    990 				0u,													// uint32_t              baseMipLevel;
    991 				1u,													// uint32_t              levelCount;
    992 				0u,													// uint32_t              baseArrayLayer;
    993 				static_cast<deUint32>(imageSize.w()),				// uint32_t              layerCount;
    994 			}
    995 		};
    996 
    997 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
    998 								0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
    999 
   1000 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
   1001 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
   1002 	}
   1003 
   1004 	// For each image layer or slice (3D), create an attachment and a pipeline
   1005 	{
   1006 		const VkImageAspectFlags	depthStencilAspect		= getFormatAspectFlags(caseDef.depthStencilFormat);
   1007 		const bool					useDepth				= (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT)   != 0;
   1008 		const bool					useStencil				= (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
   1009 		VkPipeline					basePipeline			= DE_NULL;
   1010 
   1011 		// Color attachments are first in the framebuffer
   1012 		for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
   1013 		{
   1014 			colorAttachments.push_back(makeSharedPtr(
   1015 				makeImageView(vk, device, *colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat, makeColorSubresourceRange(subpassNdx, 1))));
   1016 			attachmentHandles.push_back(**colorAttachments.back());
   1017 
   1018 			// We also have to create pipelines for each subpass
   1019 			pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(
   1020 				vk, device, basePipeline, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, imageSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
   1021 				static_cast<deUint32>(subpassNdx), useDepth, useStencil)));
   1022 
   1023 			basePipeline = **pipelines.front();
   1024 		}
   1025 
   1026 		// Then D/S attachments, if any
   1027 		if (useDepthStencil)
   1028 		for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
   1029 		{
   1030 			depthStencilAttachments.push_back(makeSharedPtr(
   1031 				makeImageView(vk, device, *depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat, makeImageSubresourceRange(depthStencilAspect, 0u, 1u, subpassNdx, 1u))));
   1032 			attachmentHandles.push_back(**depthStencilAttachments.back());
   1033 		}
   1034 	}
   1035 
   1036 	framebuffer = makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0], static_cast<deUint32>(imageSize.x()), static_cast<deUint32>(imageSize.y()));
   1037 
   1038 	{
   1039 		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
   1040 		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
   1041 
   1042 		beginCommandBuffer(vk, *cmdBuffer);
   1043 		{
   1044 			vector<VkClearValue>	clearValues	(numSlices, getClearValue(caseDef.colorFormat));
   1045 
   1046 			if (useDepthStencil)
   1047 				clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
   1048 
   1049 			const VkRect2D			renderArea	=
   1050 			{
   1051 				makeOffset2D(0, 0),
   1052 				makeExtent2D(imageSize.x(), imageSize.y()),
   1053 			};
   1054 			const VkRenderPassBeginInfo	renderPassBeginInfo	=
   1055 			{
   1056 				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// VkStructureType         sType;
   1057 				DE_NULL,									// const void*             pNext;
   1058 				*renderPass,								// VkRenderPass            renderPass;
   1059 				*framebuffer,								// VkFramebuffer           framebuffer;
   1060 				renderArea,									// VkRect2D                renderArea;
   1061 				static_cast<deUint32>(clearValues.size()),	// uint32_t                clearValueCount;
   1062 				&clearValues[0],							// const VkClearValue*     pClearValues;
   1063 			};
   1064 			const VkDeviceSize		vertexBufferOffset	= 0ull;
   1065 
   1066 			vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
   1067 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
   1068 		}
   1069 
   1070 		// Draw
   1071 		for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx)
   1072 		{
   1073 			if (subpassNdx != 0)
   1074 				vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
   1075 
   1076 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
   1077 			vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u);
   1078 		}
   1079 
   1080 		vk.cmdEndRenderPass(*cmdBuffer);
   1081 
   1082 		// Copy colorImage -> host visible colorBuffer
   1083 		{
   1084 			const VkImageMemoryBarrier	imageBarriers[]	=
   1085 			{
   1086 				{
   1087 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
   1088 					DE_NULL,										// const void*				pNext;
   1089 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags			outputMask;
   1090 					VK_ACCESS_TRANSFER_READ_BIT,					// VkAccessFlags			inputMask;
   1091 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout			oldLayout;
   1092 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,			// VkImageLayout			newLayout;
   1093 					VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
   1094 					VK_QUEUE_FAMILY_IGNORED,						// deUint32					destQueueFamilyIndex;
   1095 					*colorImage,									// VkImage					image;
   1096 					makeColorSubresourceRange(0, imageSize.w())		// VkImageSubresourceRange	subresourceRange;
   1097 				}
   1098 			};
   1099 
   1100 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
   1101 								  0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
   1102 
   1103 			// Copy the checked region rather than the whole image
   1104 			const VkImageSubresourceLayers	subresource	=
   1105 			{
   1106 				VK_IMAGE_ASPECT_COLOR_BIT,							// VkImageAspectFlags    aspectMask;
   1107 				0u,													// uint32_t              mipLevel;
   1108 				static_cast<deUint32>(checkOffset.w()),				// uint32_t              baseArrayLayer;
   1109 				static_cast<deUint32>(checkSize.w()),				// uint32_t              layerCount;
   1110 			};
   1111 
   1112 			const VkBufferImageCopy			region		=
   1113 			{
   1114 				0ull,																// VkDeviceSize                bufferOffset;
   1115 				0u,																	// uint32_t                    bufferRowLength;
   1116 				0u,																	// uint32_t                    bufferImageHeight;
   1117 				subresource,														// VkImageSubresourceLayers    imageSubresource;
   1118 				makeOffset3D(checkOffset.x(), checkOffset.y(), checkOffset.z()),	// VkOffset3D                  imageOffset;
   1119 				makeExtent3D(checkSize.swizzle(0, 1, 2)),							// VkExtent3D                  imageExtent;
   1120 			};
   1121 
   1122 			vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
   1123 
   1124 			const VkBufferMemoryBarrier	bufferBarriers[] =
   1125 			{
   1126 				{
   1127 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType    sType;
   1128 					DE_NULL,									// const void*        pNext;
   1129 					VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags      srcAccessMask;
   1130 					VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags      dstAccessMask;
   1131 					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           srcQueueFamilyIndex;
   1132 					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           dstQueueFamilyIndex;
   1133 					*colorBuffer,								// VkBuffer           buffer;
   1134 					0ull,										// VkDeviceSize       offset;
   1135 					VK_WHOLE_SIZE,								// VkDeviceSize       size;
   1136 				},
   1137 			};
   1138 
   1139 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
   1140 								  0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
   1141 		}
   1142 
   1143 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
   1144 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
   1145 	}
   1146 
   1147 	// Verify results
   1148 	{
   1149 		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
   1150 
   1151 		const tcu::TextureFormat			format			= mapVkFormat(caseDef.colorFormat);
   1152 		const int							checkDepth		= maxLayersOrDepth(checkSize);
   1153 		const int							depthOffset		= maxLayersOrDepth(checkOffset);
   1154 		const tcu::ConstPixelBufferAccess	resultImage		(format, checkSize.x(), checkSize.y(), checkDepth, colorBufferAlloc->getHostPtr());
   1155 		tcu::TextureLevel					textureLevel	(format, checkSize.x(), checkSize.y(), checkDepth);
   1156 		const tcu::PixelBufferAccess		expectedImage	= textureLevel.getAccess();
   1157 		bool								ok				= false;
   1158 
   1159 		generateExpectedImage(expectedImage, checkSize.swizzle(0, 1), depthOffset);
   1160 
   1161 		if (isFloatFormat(caseDef.colorFormat))
   1162 			ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
   1163 		else
   1164 			ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", "", expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
   1165 
   1166 		return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
   1167 	}
   1168 }
   1169 
   1170 void checkImageViewTypeRequirements (Context& context, const VkImageViewType viewType)
   1171 {
   1172 	if (viewType == VK_IMAGE_VIEW_TYPE_3D &&
   1173 		!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_maintenance1"))
   1174 		TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance1 not supported");
   1175 
   1176 	if (viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && !context.getDeviceFeatures().imageCubeArray)
   1177 		TCU_THROW(NotSupportedError, "Missing feature: imageCubeArray");
   1178 }
   1179 
   1180 //! A test that can exercise very big color and depth/stencil attachment sizes.
   1181 //! If the total memory consumed by images is too large, or if the implementation returns OUT_OF_MEMORY error somewhere,
   1182 //! the test can be retried with a next increment of size reduction index, making the attachments smaller.
   1183 tcu::TestStatus testAttachmentSize (Context& context, const CaseDef caseDef)
   1184 {
   1185 	checkImageViewTypeRequirements(context, caseDef.viewType);
   1186 
   1187 	int sizeReductionIndex = 0;
   1188 
   1189 	if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
   1190 	{
   1191 		const std::string extensionName("VK_KHR_dedicated_allocation");
   1192 
   1193 		if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName))
   1194 			TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str());
   1195 	}
   1196 
   1197 	for (;;)
   1198 	{
   1199 		try
   1200 		{
   1201 			return testWithSizeReduction(context, caseDef, sizeReductionIndex);
   1202 		}
   1203 		catch (OutOfMemoryError& ex)
   1204 		{
   1205 			context.getTestContext().getLog()
   1206 				<< tcu::TestLog::Message << "-- OutOfMemoryError: " << ex.getMessage() << tcu::TestLog::EndMessage;
   1207 
   1208 			++sizeReductionIndex;
   1209 		}
   1210 	}
   1211 	// Never reached
   1212 }
   1213 
   1214 vector<IVec4> getMipLevelSizes (IVec4 baseSize)
   1215 {
   1216 	vector<IVec4> levels;
   1217 	levels.push_back(baseSize);
   1218 
   1219 	while (baseSize.x() != 1 || baseSize.y() != 1 || baseSize.z() != 1)
   1220 	{
   1221 		baseSize.x() = deMax32(baseSize.x() >> 1, 1);
   1222 		baseSize.y() = deMax32(baseSize.y() >> 1, 1);
   1223 		baseSize.z() = deMax32(baseSize.z() >> 1, 1);
   1224 		levels.push_back(baseSize);
   1225 	}
   1226 
   1227 	return levels;
   1228 }
   1229 
   1230 //! Compute memory consumed by each mip level, including all layers. Sizes include a padding for alignment.
   1231 vector<VkDeviceSize> getPerMipLevelStorageSize (const vector<IVec4>& mipLevelSizes, const VkDeviceSize pixelSize)
   1232 {
   1233 	const deInt64			levelAlignment	= 16;
   1234 	vector<VkDeviceSize>	storageSizes;
   1235 
   1236 	for (vector<IVec4>::const_iterator it = mipLevelSizes.begin(); it != mipLevelSizes.end(); ++it)
   1237 		storageSizes.push_back(deAlign64(pixelSize * product(*it), levelAlignment));
   1238 
   1239 	return storageSizes;
   1240 }
   1241 
   1242 void drawToMipLevel (const Context&				context,
   1243 					 const CaseDef&				caseDef,
   1244 					 const int					mipLevel,
   1245 					 const IVec4&				mipSize,
   1246 					 const int					numSlices,
   1247 					 const VkImage				colorImage,
   1248 					 const VkImage				depthStencilImage,
   1249 					 const VkBuffer				vertexBuffer,
   1250 					 const VkPipelineLayout		pipelineLayout,
   1251 					 const VkShaderModule		vertexModule,
   1252 					 const VkShaderModule		fragmentModule)
   1253 {
   1254 	const DeviceInterface&			vk					= context.getDeviceInterface();
   1255 	const VkDevice					device				= context.getDevice();
   1256 	const VkQueue					queue				= context.getUniversalQueue();
   1257 	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
   1258 	const VkImageAspectFlags		depthStencilAspect	= getFormatAspectFlags(caseDef.depthStencilFormat);
   1259 	const bool						useDepth			= (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT)   != 0;
   1260 	const bool						useStencil			= (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
   1261 	const Unique<VkRenderPass>		renderPass			(makeRenderPass(vk, device, caseDef.colorFormat, caseDef.depthStencilFormat, static_cast<deUint32>(numSlices),
   1262 																		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
   1263 																		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
   1264 	vector<SharedPtrVkPipeline>		pipelines;
   1265 	vector<SharedPtrVkImageView>	colorAttachments;
   1266 	vector<SharedPtrVkImageView>	depthStencilAttachments;
   1267 	vector<VkImageView>				attachmentHandles;			// all attachments (color and d/s)
   1268 
   1269 	// For each image layer or slice (3D), create an attachment and a pipeline
   1270 	{
   1271 		VkPipeline					basePipeline			= DE_NULL;
   1272 
   1273 		// Color attachments are first in the framebuffer
   1274 		for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
   1275 		{
   1276 			colorAttachments.push_back(makeSharedPtr(makeImageView(
   1277 				vk, device, colorImage, getImageViewSliceType(caseDef.viewType), caseDef.colorFormat,
   1278 				makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, mipLevel, 1u, subpassNdx, 1u))));
   1279 			attachmentHandles.push_back(**colorAttachments.back());
   1280 
   1281 			// We also have to create pipelines for each subpass
   1282 			pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(
   1283 				vk, device, basePipeline, pipelineLayout, *renderPass, vertexModule, fragmentModule, mipSize.swizzle(0, 1), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
   1284 				static_cast<deUint32>(subpassNdx), useDepth, useStencil)));
   1285 
   1286 			basePipeline = **pipelines.front();
   1287 		}
   1288 
   1289 		// Then D/S attachments, if any
   1290 		if (useDepth || useStencil)
   1291 		for (int subpassNdx = 0; subpassNdx < numSlices; ++subpassNdx)
   1292 		{
   1293 			depthStencilAttachments.push_back(makeSharedPtr(makeImageView(
   1294 				vk, device, depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.depthStencilFormat,
   1295 				makeImageSubresourceRange(depthStencilAspect, mipLevel, 1u, subpassNdx, 1u))));
   1296 			attachmentHandles.push_back(**depthStencilAttachments.back());
   1297 		}
   1298 	}
   1299 
   1300 	const Unique<VkFramebuffer>			framebuffer (makeFramebuffer(vk, device, *renderPass, static_cast<deUint32>(attachmentHandles.size()), &attachmentHandles[0],
   1301 																	 static_cast<deUint32>(mipSize.x()), static_cast<deUint32>(mipSize.y())));
   1302 
   1303 	{
   1304 		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
   1305 		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
   1306 
   1307 		beginCommandBuffer(vk, *cmdBuffer);
   1308 		{
   1309 			vector<VkClearValue>	clearValues	(numSlices, getClearValue(caseDef.colorFormat));
   1310 
   1311 			if (useDepth || useStencil)
   1312 				clearValues.insert(clearValues.end(), numSlices, makeClearValueDepthStencil(REFERENCE_DEPTH_VALUE, REFERENCE_STENCIL_VALUE));
   1313 
   1314 			const VkRect2D			renderArea	=
   1315 			{
   1316 				makeOffset2D(0, 0),
   1317 				makeExtent2D(mipSize.x(), mipSize.y()),
   1318 			};
   1319 			const VkRenderPassBeginInfo	renderPassBeginInfo	=
   1320 			{
   1321 				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,	// VkStructureType         sType;
   1322 				DE_NULL,									// const void*             pNext;
   1323 				*renderPass,								// VkRenderPass            renderPass;
   1324 				*framebuffer,								// VkFramebuffer           framebuffer;
   1325 				renderArea,									// VkRect2D                renderArea;
   1326 				static_cast<deUint32>(clearValues.size()),	// uint32_t                clearValueCount;
   1327 				&clearValues[0],							// const VkClearValue*     pClearValues;
   1328 			};
   1329 			const VkDeviceSize		vertexBufferOffset	= 0ull;
   1330 
   1331 			vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
   1332 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
   1333 		}
   1334 
   1335 		// Draw
   1336 		for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(numSlices); ++subpassNdx)
   1337 		{
   1338 			if (subpassNdx != 0)
   1339 				vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
   1340 
   1341 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
   1342 			vk.cmdDraw(*cmdBuffer, 4u, 1u, subpassNdx*4u, 0u);
   1343 		}
   1344 
   1345 		vk.cmdEndRenderPass(*cmdBuffer);
   1346 
   1347 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
   1348 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
   1349 	}
   1350 }
   1351 
   1352 //! Use image mip levels as attachments
   1353 tcu::TestStatus testRenderToMipMaps (Context& context, const CaseDef caseDef)
   1354 {
   1355 	checkImageViewTypeRequirements(context, caseDef.viewType);
   1356 
   1357 	const DeviceInterface&			vk					= context.getDeviceInterface();
   1358 	const InstanceInterface&		vki					= context.getInstanceInterface();
   1359 	const VkDevice					device				= context.getDevice();
   1360 	const VkPhysicalDevice			physDevice			= context.getPhysicalDevice();
   1361 	const VkQueue					queue				= context.getUniversalQueue();
   1362 	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
   1363 	Allocator&						allocator			= context.getDefaultAllocator();
   1364 
   1365 	const IVec4						imageSize				= caseDef.imageSizeHint;	// MAX_SIZE is not used in this test
   1366 	const deInt32					numSlices				= maxLayersOrDepth(imageSize);
   1367 	const vector<IVec4>				mipLevelSizes			= getMipLevelSizes(imageSize);
   1368 	const vector<VkDeviceSize>		mipLevelStorageSizes	= getPerMipLevelStorageSize(mipLevelSizes, tcu::getPixelSize(mapVkFormat(caseDef.colorFormat)));
   1369 	const int						numMipLevels			= static_cast<int>(mipLevelSizes.size());
   1370 	const bool						useDepthStencil			= (caseDef.depthStencilFormat != VK_FORMAT_UNDEFINED);
   1371 
   1372 	if (caseDef.allocationKind == ALLOCATION_KIND_DEDICATED)
   1373 	{
   1374 		const std::string extensionName("VK_KHR_dedicated_allocation");
   1375 
   1376 		if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName))
   1377 			TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str());
   1378 	}
   1379 
   1380 	if (useDepthStencil && !isDepthStencilFormatSupported(vki, physDevice, caseDef.depthStencilFormat))
   1381 		TCU_THROW(NotSupportedError, "Unsupported depth/stencil format");
   1382 
   1383 	// Create a color buffer big enough to hold all layers and mip levels
   1384 	const VkDeviceSize				colorBufferSize		= sum(mipLevelStorageSizes);
   1385 	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
   1386 	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vki, vk, physDevice, device, *colorBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind));
   1387 
   1388 	{
   1389 		deMemset(colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
   1390 		flushMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
   1391 	}
   1392 
   1393 	const Unique<VkShaderModule>	vertexModule		(createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u));
   1394 	const Unique<VkShaderModule>	fragmentModule		(createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u));
   1395 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout	(vk, device));
   1396 
   1397 	Move<VkImage>					colorImage;
   1398 	MovePtr<Allocation>				colorImageAlloc;
   1399 	Move<VkImage>					depthStencilImage;
   1400 	MovePtr<Allocation>				depthStencilImageAlloc;
   1401 	Move<VkBuffer>					vertexBuffer;
   1402 	MovePtr<Allocation>				vertexBufferAlloc;
   1403 
   1404 	// Create a color image
   1405 	{
   1406 		const VkImageUsageFlags	imageUsage	= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
   1407 
   1408 		colorImage		= makeImage(vk, device, getImageCreateFlags(caseDef.viewType), getImageType(caseDef.viewType), caseDef.colorFormat,
   1409 									imageSize.swizzle(0, 1, 2), numMipLevels, imageSize.w(), imageUsage);
   1410 		colorImageAlloc	= bindImage(vki, vk, physDevice, device, *colorImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
   1411 	}
   1412 
   1413 	// Create a depth/stencil image (always a 2D image, optionally layered)
   1414 	if (useDepthStencil)
   1415 	{
   1416 		const VkImageUsageFlags	imageUsage	= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
   1417 
   1418 		depthStencilImage		= makeImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, caseDef.depthStencilFormat,
   1419 											IVec3(imageSize.x(), imageSize.y(), 1), numMipLevels, numSlices, imageUsage);
   1420 		depthStencilImageAlloc	= bindImage(vki, vk, physDevice, device, *depthStencilImage, MemoryRequirement::Any, allocator, caseDef.allocationKind);
   1421 	}
   1422 
   1423 	// Create a vertex buffer
   1424 	{
   1425 		const vector<Vertex4RGBA>	vertices			= genFullQuadVertices(numSlices);
   1426 		const VkDeviceSize			vertexBufferSize	= sizeInBytes(vertices);
   1427 
   1428 		vertexBuffer		= makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
   1429 		vertexBufferAlloc	= bindBuffer(vki, vk, physDevice, device, *vertexBuffer, MemoryRequirement::HostVisible, allocator, caseDef.allocationKind);
   1430 
   1431 		deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
   1432 		flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
   1433 	}
   1434 
   1435 	// Prepare images
   1436 	{
   1437 		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
   1438 		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
   1439 
   1440 		beginCommandBuffer(vk, *cmdBuffer);
   1441 
   1442 		const VkImageMemoryBarrier	imageBarriers[]	=
   1443 		{
   1444 			{
   1445 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// VkStructureType            sType;
   1446 				DE_NULL,											// const void*                pNext;
   1447 				(VkAccessFlags)0,									// VkAccessFlags              srcAccessMask;
   1448 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,				// VkAccessFlags              dstAccessMask;
   1449 				VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout              oldLayout;
   1450 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout              newLayout;
   1451 				VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   srcQueueFamilyIndex;
   1452 				VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   dstQueueFamilyIndex;
   1453 				*colorImage,										// VkImage                    image;
   1454 				{													// VkImageSubresourceRange    subresourceRange;
   1455 					VK_IMAGE_ASPECT_COLOR_BIT,							// VkImageAspectFlags    aspectMask;
   1456 					0u,													// uint32_t              baseMipLevel;
   1457 					static_cast<deUint32>(numMipLevels),				// uint32_t              levelCount;
   1458 					0u,													// uint32_t              baseArrayLayer;
   1459 					static_cast<deUint32>(imageSize.w()),				// uint32_t              layerCount;
   1460 				},
   1461 			},
   1462 			{
   1463 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,				// VkStructureType            sType;
   1464 				DE_NULL,											// const void*                pNext;
   1465 				(VkAccessFlags)0,									// VkAccessFlags              srcAccessMask;
   1466 				VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,		// VkAccessFlags              dstAccessMask;
   1467 				VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout              oldLayout;
   1468 				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout              newLayout;
   1469 				VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   srcQueueFamilyIndex;
   1470 				VK_QUEUE_FAMILY_IGNORED,							// uint32_t                   dstQueueFamilyIndex;
   1471 				*depthStencilImage,									// VkImage                    image;
   1472 				{													// VkImageSubresourceRange    subresourceRange;
   1473 					getFormatAspectFlags(caseDef.depthStencilFormat),	// VkImageAspectFlags    aspectMask;
   1474 					0u,													// uint32_t              baseMipLevel;
   1475 					static_cast<deUint32>(numMipLevels),				// uint32_t              levelCount;
   1476 					0u,													// uint32_t              baseArrayLayer;
   1477 					static_cast<deUint32>(numSlices),					// uint32_t              layerCount;
   1478 				},
   1479 			}
   1480 		};
   1481 
   1482 		const deUint32	numImageBarriers = static_cast<deUint32>(DE_LENGTH_OF_ARRAY(imageBarriers) - (useDepthStencil ? 0 : 1));
   1483 
   1484 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
   1485 								0u, DE_NULL, 0u, DE_NULL, numImageBarriers, imageBarriers);
   1486 
   1487 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
   1488 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
   1489 	}
   1490 
   1491 	// Draw
   1492 	for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
   1493 	{
   1494 		const IVec4&	mipSize		= mipLevelSizes[mipLevel];
   1495 		const int		levelSlices	= maxLayersOrDepth(mipSize);
   1496 
   1497 		drawToMipLevel (context, caseDef, mipLevel, mipSize, levelSlices, *colorImage, *depthStencilImage, *vertexBuffer, *pipelineLayout,
   1498 						*vertexModule, *fragmentModule);
   1499 	}
   1500 
   1501 	// Copy results: colorImage -> host visible colorBuffer
   1502 	{
   1503 		const Unique<VkCommandPool>		cmdPool		(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
   1504 		const Unique<VkCommandBuffer>	cmdBuffer	(makeCommandBuffer(vk, device, *cmdPool));
   1505 
   1506 		beginCommandBuffer(vk, *cmdBuffer);
   1507 
   1508 		{
   1509 			const VkImageMemoryBarrier	imageBarriers[]	=
   1510 			{
   1511 				{
   1512 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType            sType;
   1513 					DE_NULL,										// const void*                pNext;
   1514 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags              srcAccessMask;
   1515 					VK_ACCESS_TRANSFER_READ_BIT,					// VkAccessFlags              dstAccessMask;
   1516 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout              oldLayout;
   1517 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,			// VkImageLayout              newLayout;
   1518 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t                   srcQueueFamilyIndex;
   1519 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t                   dstQueueFamilyIndex;
   1520 					*colorImage,									// VkImage                    image;
   1521 					{												// VkImageSubresourceRange    subresourceRange;
   1522 						VK_IMAGE_ASPECT_COLOR_BIT,							// VkImageAspectFlags    aspectMask;
   1523 						0u,													// uint32_t              baseMipLevel;
   1524 						static_cast<deUint32>(numMipLevels),				// uint32_t              levelCount;
   1525 						0u,													// uint32_t              baseArrayLayer;
   1526 						static_cast<deUint32>(imageSize.w()),				// uint32_t              layerCount;
   1527 					},
   1528 				}
   1529 			};
   1530 
   1531 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
   1532 									0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
   1533 		}
   1534 		{
   1535 			vector<VkBufferImageCopy>	regions;
   1536 			VkDeviceSize				levelOffset = 0ull;
   1537 			VkBufferImageCopy			workRegion	=
   1538 			{
   1539 				0ull,																				// VkDeviceSize                bufferOffset;
   1540 				0u,																					// uint32_t                    bufferRowLength;
   1541 				0u,																					// uint32_t                    bufferImageHeight;
   1542 				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageSize.w()),		// VkImageSubresourceLayers    imageSubresource;
   1543 				makeOffset3D(0, 0, 0),																// VkOffset3D                  imageOffset;
   1544 				makeExtent3D(0, 0, 0),																// VkExtent3D                  imageExtent;
   1545 			};
   1546 
   1547 			for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
   1548 			{
   1549 				workRegion.bufferOffset					= levelOffset;
   1550 				workRegion.imageSubresource.mipLevel	= static_cast<deUint32>(mipLevel);
   1551 				workRegion.imageExtent					= makeExtent3D(mipLevelSizes[mipLevel].swizzle(0, 1, 2));
   1552 
   1553 				regions.push_back(workRegion);
   1554 
   1555 				levelOffset += mipLevelStorageSizes[mipLevel];
   1556 			}
   1557 
   1558 			vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, static_cast<deUint32>(regions.size()), &regions[0]);
   1559 		}
   1560 		{
   1561 			const VkBufferMemoryBarrier	bufferBarriers[] =
   1562 			{
   1563 				{
   1564 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType    sType;
   1565 					DE_NULL,									// const void*        pNext;
   1566 					VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags      srcAccessMask;
   1567 					VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags      dstAccessMask;
   1568 					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           srcQueueFamilyIndex;
   1569 					VK_QUEUE_FAMILY_IGNORED,					// uint32_t           dstQueueFamilyIndex;
   1570 					*colorBuffer,								// VkBuffer           buffer;
   1571 					0ull,										// VkDeviceSize       offset;
   1572 					VK_WHOLE_SIZE,								// VkDeviceSize       size;
   1573 				},
   1574 			};
   1575 
   1576 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
   1577 									0u, DE_NULL, DE_LENGTH_OF_ARRAY(bufferBarriers), bufferBarriers, 0u, DE_NULL);
   1578 		}
   1579 
   1580 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
   1581 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
   1582 	}
   1583 
   1584 	// Verify results (per mip level)
   1585 	{
   1586 		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
   1587 
   1588 		const tcu::TextureFormat			format			= mapVkFormat(caseDef.colorFormat);
   1589 
   1590 		VkDeviceSize						levelOffset		= 0ull;
   1591 		bool								allOk			= true;
   1592 
   1593 		for (int mipLevel = 0; mipLevel < numMipLevels; ++mipLevel)
   1594 		{
   1595 			const IVec4&						mipSize			= mipLevelSizes[mipLevel];
   1596 			const void*	const					pLevelData		= static_cast<const deUint8*>(colorBufferAlloc->getHostPtr()) + levelOffset;
   1597 			const int							levelDepth		= maxLayersOrDepth(mipSize);
   1598 			const tcu::ConstPixelBufferAccess	resultImage		(format, mipSize.x(), mipSize.y(), levelDepth, pLevelData);
   1599 			tcu::TextureLevel					textureLevel	(format, mipSize.x(), mipSize.y(), levelDepth);
   1600 			const tcu::PixelBufferAccess		expectedImage	= textureLevel.getAccess();
   1601 			const std::string					comparisonName	= "Mip level " + de::toString(mipLevel);
   1602 			bool								ok				= false;
   1603 
   1604 			generateExpectedImage(expectedImage, mipSize.swizzle(0, 1), 0);
   1605 
   1606 			if (isFloatFormat(caseDef.colorFormat))
   1607 				ok = tcu::floatThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
   1608 			else
   1609 				ok = tcu::intThresholdCompare(context.getTestContext().getLog(), "Image Comparison", comparisonName.c_str(), expectedImage, resultImage, tcu::UVec4(2), tcu::COMPARE_LOG_RESULT);
   1610 
   1611 			allOk		=  allOk && ok;	// keep testing all levels, even if we know it's a fail overall
   1612 			levelOffset += mipLevelStorageSizes[mipLevel];
   1613 		}
   1614 
   1615 		return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
   1616 	}
   1617 }
   1618 
   1619 std::string getSizeDescription (const IVec4& size)
   1620 {
   1621 	std::ostringstream str;
   1622 
   1623 	const char* const description[4] =
   1624 	{
   1625 		"width", "height", "depth", "layers"
   1626 	};
   1627 
   1628 	int numMaxComponents = 0;
   1629 
   1630 	for (int i = 0; i < 4; ++i)
   1631 	{
   1632 		if (size[i] == MAX_SIZE)
   1633 		{
   1634 			if (numMaxComponents > 0)
   1635 				str << "_";
   1636 
   1637 			str << description[i];
   1638 			++numMaxComponents;
   1639 		}
   1640 	}
   1641 
   1642 	if (numMaxComponents == 0)
   1643 		str << "small";
   1644 
   1645 	return str.str();
   1646 }
   1647 
   1648 inline std::string getFormatString (const VkFormat format)
   1649 {
   1650 	std::string name(getFormatName(format));
   1651 	return de::toLower(name.substr(10));
   1652 }
   1653 
   1654 std::string getFormatString (const VkFormat colorFormat, const VkFormat depthStencilFormat)
   1655 {
   1656 	std::ostringstream str;
   1657 	str << getFormatString(colorFormat);
   1658 	if (depthStencilFormat != VK_FORMAT_UNDEFINED)
   1659 		str << "_" << getFormatString(depthStencilFormat);
   1660 	return str.str();
   1661 }
   1662 
   1663 std::string getShortImageViewTypeName (const VkImageViewType imageViewType)
   1664 {
   1665 	std::string s(getImageViewTypeName(imageViewType));
   1666 	return de::toLower(s.substr(19));
   1667 }
   1668 
   1669 inline BVec4 bvecFromMask (deUint32 mask)
   1670 {
   1671 	return BVec4((mask >> 0) & 1,
   1672 				 (mask >> 1) & 1,
   1673 				 (mask >> 2) & 1,
   1674 				 (mask >> 3) & 1);
   1675 }
   1676 
   1677 vector<IVec4> genSizeCombinations (const IVec4& baselineSize, const deUint32 sizeMask, const VkImageViewType imageViewType)
   1678 {
   1679 	vector<IVec4>		sizes;
   1680 	std::set<deUint32>	masks;
   1681 
   1682 	for (deUint32 i = 0; i < (1u << 4); ++i)
   1683 	{
   1684 		// Cube images have square faces
   1685 		if (isCube(imageViewType) && ((i & MASK_WH) != 0))
   1686 			i |= MASK_WH;
   1687 
   1688 		masks.insert(i & sizeMask);
   1689 	}
   1690 
   1691 	for (std::set<deUint32>::const_iterator it = masks.begin(); it != masks.end(); ++it)
   1692 		sizes.push_back(tcu::select(IVec4(MAX_SIZE), baselineSize, bvecFromMask(*it)));
   1693 
   1694 	return sizes;
   1695 }
   1696 
   1697 void addTestCasesWithFunctions (tcu::TestCaseGroup* group, AllocationKind allocationKind)
   1698 {
   1699 	const struct
   1700 	{
   1701 		VkImageViewType		viewType;
   1702 		IVec4				baselineSize;	//!< image size: (dimX, dimY, dimZ, arraySize)
   1703 		deUint32			sizeMask;		//!< if a dimension is masked, generate a huge size case for it
   1704 	} testCase[] =
   1705 	{
   1706 		{ VK_IMAGE_VIEW_TYPE_1D,			IVec4(54,  1, 1,   1),	MASK_W			},
   1707 		{ VK_IMAGE_VIEW_TYPE_1D_ARRAY,		IVec4(54,  1, 1,   4),	MASK_W_LAYERS	},
   1708 		{ VK_IMAGE_VIEW_TYPE_2D,			IVec4(44, 23, 1,   1),	MASK_WH			},
   1709 		{ VK_IMAGE_VIEW_TYPE_2D_ARRAY,		IVec4(44, 23, 1,   4),	MASK_WH_LAYERS	},
   1710 		{ VK_IMAGE_VIEW_TYPE_3D,			IVec4(22, 31, 7,   1),	MASK_WHD		},
   1711 		{ VK_IMAGE_VIEW_TYPE_CUBE,			IVec4(35, 35, 1,   6),	MASK_WH			},
   1712 		{ VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,	IVec4(35, 35, 1, 2*6),	MASK_WH_LAYERS	},
   1713 	};
   1714 
   1715 	const VkFormat format[]	=
   1716 	{
   1717 		VK_FORMAT_R8G8B8A8_UNORM,
   1718 		VK_FORMAT_R32_UINT,
   1719 		VK_FORMAT_R16G16_SINT,
   1720 		VK_FORMAT_R32G32B32A32_SFLOAT,
   1721 	};
   1722 
   1723 	const VkFormat depthStencilFormat[] =
   1724 	{
   1725 		VK_FORMAT_UNDEFINED,			// don't use a depth/stencil attachment
   1726 		VK_FORMAT_D16_UNORM,
   1727 		VK_FORMAT_S8_UINT,
   1728 		VK_FORMAT_D24_UNORM_S8_UINT,	// one of the following mixed formats must be supported
   1729 		VK_FORMAT_D32_SFLOAT_S8_UINT,
   1730 	};
   1731 
   1732 	for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCase); ++caseNdx)
   1733 	{
   1734 		MovePtr<tcu::TestCaseGroup>	imageGroup(new tcu::TestCaseGroup(group->getTestContext(), getShortImageViewTypeName(testCase[caseNdx].viewType).c_str(), ""));
   1735 
   1736 		// Generate attachment size cases
   1737 		{
   1738 			const vector<IVec4> sizes = genSizeCombinations(testCase[caseNdx].baselineSize, testCase[caseNdx].sizeMask, testCase[caseNdx].viewType);
   1739 
   1740 			MovePtr<tcu::TestCaseGroup>	smallGroup(new tcu::TestCaseGroup(group->getTestContext(), "small", ""));
   1741 			MovePtr<tcu::TestCaseGroup>	hugeGroup (new tcu::TestCaseGroup(group->getTestContext(), "huge",  ""));
   1742 
   1743 			imageGroup->addChild(smallGroup.get());
   1744 			imageGroup->addChild(hugeGroup.get());
   1745 
   1746 			for (vector<IVec4>::const_iterator sizeIter = sizes.begin(); sizeIter != sizes.end(); ++sizeIter)
   1747 			{
   1748 				// The first size is the baseline size, put it in a dedicated group
   1749 				if (sizeIter == sizes.begin())
   1750 				{
   1751 					for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
   1752 					for (int formatNdx   = 0; formatNdx   < DE_LENGTH_OF_ARRAY(format);             ++formatNdx)
   1753 					{
   1754 						const CaseDef caseDef =
   1755 						{
   1756 							testCase[caseNdx].viewType,			// VkImageViewType	imageType;
   1757 							*sizeIter,							// IVec4			imageSizeHint;
   1758 							format[formatNdx],					// VkFormat			colorFormat;
   1759 							depthStencilFormat[dsFormatNdx],	// VkFormat			depthStencilFormat;
   1760 							allocationKind						// AllocationKind	allocationKind;
   1761 						};
   1762 						addFunctionCaseWithPrograms(smallGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", initPrograms, testAttachmentSize, caseDef);
   1763 					}
   1764 				}
   1765 				else // All huge cases go into a separate group
   1766 				{
   1767 					if (allocationKind != ALLOCATION_KIND_DEDICATED)
   1768 					{
   1769 						MovePtr<tcu::TestCaseGroup>	sizeGroup	(new tcu::TestCaseGroup(group->getTestContext(), getSizeDescription(*sizeIter).c_str(), ""));
   1770 						const VkFormat				colorFormat	= VK_FORMAT_R8G8B8A8_UNORM;
   1771 
   1772 						// Use the same color format for all cases, to reduce the number of permutations
   1773 						for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
   1774 						{
   1775 							const CaseDef caseDef =
   1776 							{
   1777 								testCase[caseNdx].viewType,			// VkImageViewType	viewType;
   1778 								*sizeIter,							// IVec4			imageSizeHint;
   1779 								colorFormat,						// VkFormat			colorFormat;
   1780 								depthStencilFormat[dsFormatNdx],	// VkFormat			depthStencilFormat;
   1781 								allocationKind						// AllocationKind	allocationKind;
   1782 							};
   1783 							addFunctionCaseWithPrograms(sizeGroup.get(), getFormatString(colorFormat, depthStencilFormat[dsFormatNdx]), "", initPrograms, testAttachmentSize, caseDef);
   1784 						}
   1785 						hugeGroup->addChild(sizeGroup.release());
   1786 					}
   1787 				}
   1788 			}
   1789 			smallGroup.release();
   1790 			hugeGroup.release();
   1791 		}
   1792 
   1793 		// Generate mip map cases
   1794 		{
   1795 			MovePtr<tcu::TestCaseGroup>	mipmapGroup(new tcu::TestCaseGroup(group->getTestContext(), "mipmap", ""));
   1796 
   1797 			for (int dsFormatNdx = 0; dsFormatNdx < DE_LENGTH_OF_ARRAY(depthStencilFormat); ++dsFormatNdx)
   1798 			for (int formatNdx   = 0; formatNdx   < DE_LENGTH_OF_ARRAY(format);             ++formatNdx)
   1799 			{
   1800 				const CaseDef caseDef =
   1801 				{
   1802 					testCase[caseNdx].viewType,			// VkImageViewType	imageType;
   1803 					testCase[caseNdx].baselineSize,		// IVec4			imageSizeHint;
   1804 					format[formatNdx],					// VkFormat			colorFormat;
   1805 					depthStencilFormat[dsFormatNdx],	// VkFormat			depthStencilFormat;
   1806 					allocationKind						// AllocationKind	allocationKind;
   1807 				};
   1808 				addFunctionCaseWithPrograms(mipmapGroup.get(), getFormatString(format[formatNdx], depthStencilFormat[dsFormatNdx]), "", initPrograms, testRenderToMipMaps, caseDef);
   1809 			}
   1810 			imageGroup->addChild(mipmapGroup.release());
   1811 		}
   1812 
   1813 		group->addChild(imageGroup.release());
   1814 	}
   1815 }
   1816 
   1817 void addCoreRenderToImageTests (tcu::TestCaseGroup* group)
   1818 {
   1819 	addTestCasesWithFunctions(group, ALLOCATION_KIND_SUBALLOCATED);
   1820 }
   1821 
   1822 void addDedicatedAllocationRenderToImageTests (tcu::TestCaseGroup* group)
   1823 {
   1824 	addTestCasesWithFunctions(group, ALLOCATION_KIND_DEDICATED);
   1825 }
   1826 
   1827 } // anonymous ns
   1828 
   1829 tcu::TestCaseGroup* createRenderToImageTests (tcu::TestContext& testCtx)
   1830 {
   1831 	de::MovePtr<tcu::TestCaseGroup>	renderToImageTests	(new tcu::TestCaseGroup(testCtx, "render_to_image", "Render to image tests"));
   1832 
   1833 	renderToImageTests->addChild(createTestGroup(testCtx, "core",					"Core render to image tests",								addCoreRenderToImageTests));
   1834 	renderToImageTests->addChild(createTestGroup(testCtx, "dedicated_allocation",	"Render to image tests for dedicated memory allocation",	addDedicatedAllocationRenderToImageTests));
   1835 
   1836 	return renderToImageTests.release();
   1837 }
   1838 
   1839 } // pipeline
   1840 } // vkt
   1841