Home | History | Annotate | Download | only in fragment_ops
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2016 The Khronos Group Inc.
      6  * Copyright (c) 2014 The Android Open Source Project
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  *//*!
     21  * \file
     22  * \brief Scissor multi viewport tests
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
     26 #include "vktTestCaseUtil.hpp"
     27 #include "vktFragmentOperationsMakeUtil.hpp"
     28 
     29 #include "vkDefs.hpp"
     30 #include "vkRefUtil.hpp"
     31 #include "vkTypeUtil.hpp"
     32 #include "vkMemUtil.hpp"
     33 #include "vkPrograms.hpp"
     34 #include "vkImageUtil.hpp"
     35 #include "vkQueryUtil.hpp"
     36 
     37 #include "tcuTestLog.hpp"
     38 #include "tcuVector.hpp"
     39 #include "tcuImageCompare.hpp"
     40 #include "tcuTextureUtil.hpp"
     41 
     42 #include "deUniquePtr.hpp"
     43 #include "deMath.h"
     44 
     45 namespace vkt
     46 {
     47 namespace FragmentOperations
     48 {
     49 using namespace vk;
     50 using de::UniquePtr;
     51 using de::MovePtr;
     52 using tcu::Vec4;
     53 using tcu::Vec2;
     54 using tcu::IVec2;
     55 using tcu::IVec4;
     56 
     57 namespace
     58 {
     59 
     60 enum Constants
     61 {
     62 	MIN_MAX_VIEWPORTS = 16,		//!< Minimum number of viewports for an implementation supporting multiViewport.
     63 };
     64 
     65 template<typename T>
     66 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
     67 {
     68 	return vec.size() * sizeof(vec[0]);
     69 }
     70 
     71 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
     72 {
     73 	const VkImageCreateInfo imageParams =
     74 	{
     75 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
     76 		DE_NULL,										// const void*				pNext;
     77 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
     78 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
     79 		format,											// VkFormat					format;
     80 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
     81 		1u,												// deUint32					mipLevels;
     82 		1u,												// deUint32					arrayLayers;
     83 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
     84 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
     85 		usage,											// VkImageUsageFlags		usage;
     86 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
     87 		0u,												// deUint32					queueFamilyIndexCount;
     88 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
     89 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
     90 	};
     91 	return imageParams;
     92 }
     93 
     94 //! A single-attachment, single-subpass render pass.
     95 Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
     96 								   const VkDevice			device,
     97 								   const VkFormat			colorFormat)
     98 {
     99 	const VkAttachmentDescription colorAttachmentDescription =
    100 	{
    101 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    102 		colorFormat,										// VkFormat							format;
    103 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    104 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    105 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
    106 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
    107 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    108 		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
    109 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
    110 	};
    111 
    112 	const VkAttachmentReference colorAttachmentRef =
    113 	{
    114 		0u,													// deUint32			attachment;
    115 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
    116 	};
    117 
    118 	const VkSubpassDescription subpassDescription =
    119 	{
    120 		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
    121 		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
    122 		0u,													// deUint32							inputAttachmentCount;
    123 		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
    124 		1u,													// deUint32							colorAttachmentCount;
    125 		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
    126 		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
    127 		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
    128 		0u,													// deUint32							preserveAttachmentCount;
    129 		DE_NULL												// const deUint32*					pPreserveAttachments;
    130 	};
    131 
    132 	const VkRenderPassCreateInfo renderPassInfo =
    133 	{
    134 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
    135 		DE_NULL,											// const void*						pNext;
    136 		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
    137 		1u,													// deUint32							attachmentCount;
    138 		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
    139 		1u,													// deUint32							subpassCount;
    140 		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
    141 		0u,													// deUint32							dependencyCount;
    142 		DE_NULL												// const VkSubpassDependency*		pDependencies;
    143 	};
    144 
    145 	return createRenderPass(vk, device, &renderPassInfo);
    146 }
    147 
    148 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
    149 									   const VkDevice				device,
    150 									   const VkPipelineLayout		pipelineLayout,
    151 									   const VkRenderPass			renderPass,
    152 									   const VkShaderModule			vertexModule,
    153 									   const VkShaderModule			geometryModule,
    154 									   const VkShaderModule			fragmentModule,
    155 									   const IVec2					renderSize,
    156 									   const int					numViewports,
    157 									   const std::vector<IVec4>		scissors)
    158 {
    159 	const VkVertexInputBindingDescription vertexInputBindingDescription =
    160 	{
    161 		0u,								// uint32_t				binding;
    162 		sizeof(Vec4),					// uint32_t				stride;
    163 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
    164 	};
    165 
    166 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
    167 	{
    168 		{
    169 			0u,									// uint32_t			location;
    170 			0u,									// uint32_t			binding;
    171 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
    172 			0u,									// uint32_t			offset;
    173 		},
    174 	};
    175 
    176 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
    177 	{
    178 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
    179 		DE_NULL,														// const void*                                 pNext;
    180 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
    181 		1u,																// uint32_t                                    vertexBindingDescriptionCount;
    182 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    183 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
    184 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
    185 	};
    186 
    187 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
    188 	{
    189 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
    190 		DE_NULL,														// const void*                                 pNext;
    191 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
    192 		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,								// VkPrimitiveTopology                         topology;
    193 		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
    194 	};
    195 
    196 	const VkViewport defaultViewport = makeViewport(
    197 		0.0f, 0.0f,
    198 		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
    199 		0.0f, 1.0f);
    200 	const std::vector<VkViewport> viewports(numViewports, defaultViewport);
    201 
    202 	DE_ASSERT(numViewports == static_cast<int>(scissors.size()));
    203 
    204 	std::vector<VkRect2D> rectScissors;
    205 	rectScissors.reserve(numViewports);
    206 
    207 	for (std::vector<IVec4>::const_iterator it = scissors.begin(); it != scissors.end(); ++it)
    208 	{
    209 		const VkRect2D rect =
    210 		{
    211 			makeOffset2D(it->x(), it->y()),
    212 			makeExtent2D(static_cast<deUint32>(it->z()), static_cast<deUint32>(it->w())),
    213 		};
    214 		rectScissors.push_back(rect);
    215 	}
    216 
    217 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
    218 	{
    219 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
    220 		DE_NULL,														// const void*                                 pNext;
    221 		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
    222 		static_cast<deUint32>(numViewports),							// uint32_t                                    viewportCount;
    223 		&viewports[0],													// const VkViewport*                           pViewports;
    224 		static_cast<deUint32>(numViewports),							// uint32_t                                    scissorCount;
    225 		&rectScissors[0],												// const VkRect2D*                             pScissors;
    226 	};
    227 
    228 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
    229 	{
    230 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
    231 		DE_NULL,														// const void*                              pNext;
    232 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
    233 		VK_FALSE,														// VkBool32                                 depthClampEnable;
    234 		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
    235 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
    236 		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
    237 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
    238 		VK_FALSE,														// VkBool32									depthBiasEnable;
    239 		0.0f,															// float									depthBiasConstantFactor;
    240 		0.0f,															// float									depthBiasClamp;
    241 		0.0f,															// float									depthBiasSlopeFactor;
    242 		1.0f,															// float									lineWidth;
    243 	};
    244 
    245 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
    246 	{
    247 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
    248 		DE_NULL,														// const void*								pNext;
    249 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
    250 		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
    251 		VK_FALSE,														// VkBool32									sampleShadingEnable;
    252 		0.0f,															// float									minSampleShading;
    253 		DE_NULL,														// const VkSampleMask*						pSampleMask;
    254 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
    255 		VK_FALSE														// VkBool32									alphaToOneEnable;
    256 	};
    257 
    258 	const VkStencilOpState stencilOpState = makeStencilOpState(
    259 		VK_STENCIL_OP_KEEP,				// stencil fail
    260 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
    261 		VK_STENCIL_OP_KEEP,				// depth only fail
    262 		VK_COMPARE_OP_ALWAYS,			// compare op
    263 		0u,								// compare mask
    264 		0u,								// write mask
    265 		0u);							// reference
    266 
    267 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
    268 	{
    269 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
    270 		DE_NULL,														// const void*								pNext;
    271 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
    272 		VK_FALSE,														// VkBool32									depthTestEnable;
    273 		VK_FALSE,														// VkBool32									depthWriteEnable;
    274 		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
    275 		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
    276 		VK_FALSE,														// VkBool32									stencilTestEnable;
    277 		stencilOpState,													// VkStencilOpState							front;
    278 		stencilOpState,													// VkStencilOpState							back;
    279 		0.0f,															// float									minDepthBounds;
    280 		1.0f,															// float									maxDepthBounds;
    281 	};
    282 
    283 	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    284 	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
    285 	{
    286 		VK_FALSE,						// VkBool32					blendEnable;
    287 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
    288 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
    289 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
    290 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
    291 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
    292 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
    293 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
    294 	};
    295 
    296 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
    297 	{
    298 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
    299 		DE_NULL,														// const void*									pNext;
    300 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
    301 		VK_FALSE,														// VkBool32										logicOpEnable;
    302 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
    303 		1u,																// deUint32										attachmentCount;
    304 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
    305 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
    306 	};
    307 
    308 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
    309 	{
    310 		{
    311 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
    312 			DE_NULL,													// const void*							pNext;
    313 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
    314 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
    315 			vertexModule,												// VkShaderModule						module;
    316 			"main",														// const char*							pName;
    317 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
    318 		},
    319 		{
    320 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
    321 			DE_NULL,													// const void*							pNext;
    322 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
    323 			VK_SHADER_STAGE_GEOMETRY_BIT,								// VkShaderStageFlagBits				stage;
    324 			geometryModule,												// VkShaderModule						module;
    325 			"main",														// const char*							pName;
    326 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
    327 		},
    328 		{
    329 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
    330 			DE_NULL,													// const void*							pNext;
    331 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
    332 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
    333 			fragmentModule,												// VkShaderModule						module;
    334 			"main",														// const char*							pName;
    335 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
    336 		},
    337 	};
    338 
    339 	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
    340 	{
    341 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
    342 		DE_NULL,											// const void*										pNext;
    343 		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
    344 		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
    345 		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
    346 		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
    347 		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
    348 		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
    349 		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
    350 		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
    351 		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
    352 		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
    353 		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
    354 		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
    355 		pipelineLayout,										// VkPipelineLayout									layout;
    356 		renderPass,											// VkRenderPass										renderPass;
    357 		0u,													// deUint32											subpass;
    358 		DE_NULL,											// VkPipeline										basePipelineHandle;
    359 		0,													// deInt32											basePipelineIndex;
    360 	};
    361 
    362 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
    363 }
    364 
    365 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
    366 {
    367 	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
    368 	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
    369 }
    370 
    371 void requireFeatureMultiViewport (const InstanceInterface& vki, const VkPhysicalDevice physDevice)
    372 {
    373 	const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(vki, physDevice);
    374 	const VkPhysicalDeviceLimits	limits		= getPhysicalDeviceProperties(vki, physDevice).limits;
    375 
    376 	if (!features.geometryShader)
    377 		TCU_THROW(NotSupportedError, "Required feature is not supported: geometryShader");
    378 
    379 	if (!features.multiViewport)
    380 		TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
    381 
    382 	if (limits.maxViewports < MIN_MAX_VIEWPORTS)
    383 		TCU_THROW(NotSupportedError, "Implementation doesn't support minimum required number of viewports");
    384 }
    385 
    386 std::vector<IVec4> generateScissors (const int numScissors, const IVec2& renderSize)
    387 {
    388 	// Scissor rects will be arranged in a grid-like fashion.
    389 
    390 	const int numCols		= deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numScissors)));
    391 	const int numRows		= deCeilFloatToInt32(static_cast<float>(numScissors) / static_cast<float>(numCols));
    392 	const int rectWidth		= renderSize.x() / numCols;
    393 	const int rectHeight	= renderSize.y() / numRows;
    394 
    395 	std::vector<IVec4> scissors;
    396 	scissors.reserve(numScissors);
    397 
    398 	int x = 0;
    399 	int y = 0;
    400 
    401 	for (int scissorNdx = 0; scissorNdx < numScissors; ++scissorNdx)
    402 	{
    403 		const bool nextRow = (scissorNdx != 0) && (scissorNdx % numCols == 0);
    404 		if (nextRow)
    405 		{
    406 			x  = 0;
    407 			y += rectHeight;
    408 		}
    409 
    410 		scissors.push_back(IVec4(x, y, rectWidth, rectHeight));
    411 
    412 		x += rectWidth;
    413 	}
    414 
    415 	return scissors;
    416 }
    417 
    418 std::vector<Vec4> generateColors (const int numColors)
    419 {
    420 	const Vec4 colors[] =
    421 	{
    422 		Vec4(0.18f, 0.42f, 0.17f, 1.0f),
    423 		Vec4(0.29f, 0.62f, 0.28f, 1.0f),
    424 		Vec4(0.59f, 0.84f, 0.44f, 1.0f),
    425 		Vec4(0.96f, 0.95f, 0.72f, 1.0f),
    426 		Vec4(0.94f, 0.55f, 0.39f, 1.0f),
    427 		Vec4(0.82f, 0.19f, 0.12f, 1.0f),
    428 		Vec4(0.46f, 0.15f, 0.26f, 1.0f),
    429 		Vec4(0.24f, 0.14f, 0.24f, 1.0f),
    430 		Vec4(0.49f, 0.31f, 0.26f, 1.0f),
    431 		Vec4(0.78f, 0.52f, 0.33f, 1.0f),
    432 		Vec4(0.94f, 0.82f, 0.31f, 1.0f),
    433 		Vec4(0.98f, 0.65f, 0.30f, 1.0f),
    434 		Vec4(0.22f, 0.65f, 0.53f, 1.0f),
    435 		Vec4(0.67f, 0.81f, 0.91f, 1.0f),
    436 		Vec4(0.43f, 0.44f, 0.75f, 1.0f),
    437 		Vec4(0.26f, 0.24f, 0.48f, 1.0f),
    438 	};
    439 
    440 	DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
    441 
    442 	return std::vector<Vec4>(colors, colors + numColors);
    443 }
    444 
    445 //! Renders a colorful grid of rectangles.
    446 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat	format,
    447 										  const IVec2&				renderSize,
    448 										  const Vec4&				clearColor,
    449 										  const std::vector<IVec4>&	scissors,
    450 										  const std::vector<Vec4>&	scissorColors)
    451 {
    452 	DE_ASSERT(scissors.size() == scissorColors.size());
    453 
    454 	tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
    455 	tcu::clear(image.getAccess(), clearColor);
    456 
    457 	for (std::size_t i = 0; i < scissors.size(); ++i)
    458 	{
    459 		tcu::clear(
    460 			tcu::getSubregion(image.getAccess(), scissors[i].x(), scissors[i].y(), scissors[i].z(), scissors[i].w()),
    461 			scissorColors[i]);
    462 	}
    463 
    464 	return image;
    465 }
    466 
    467 void initPrograms (SourceCollections& programCollection, const int numViewports)
    468 {
    469 	DE_UNREF(numViewports);
    470 
    471 	// Vertex shader
    472 	{
    473 		std::ostringstream src;
    474 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    475 			<< "\n"
    476 			<< "layout(location = 0) in  vec4 in_color;\n"
    477 			<< "layout(location = 0) out vec4 out_color;\n"
    478 			<< "\n"
    479 			<< "void main(void)\n"
    480 			<< "{\n"
    481 			<< "    out_color = in_color;\n"
    482 			<< "}\n";
    483 
    484 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    485 	}
    486 
    487 	// Geometry shader
    488 	{
    489 		// Each input point generates a fullscreen quad.
    490 
    491 		std::ostringstream src;
    492 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    493 			<< "\n"
    494 			<< "layout(points) in;\n"
    495 			<< "layout(triangle_strip, max_vertices=4) out;\n"
    496 			<< "\n"
    497 			<< "out gl_PerVertex {\n"
    498 			<< "    vec4 gl_Position;\n"
    499 			<< "};\n"
    500 			<< "\n"
    501 			<< "layout(location = 0) in  vec4 in_color[];\n"
    502 			<< "layout(location = 0) out vec4 out_color;\n"
    503 			<< "\n"
    504 			<< "void main(void)\n"
    505 			<< "{\n"
    506 			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
    507 			<< "    gl_Position      = vec4(-1.0, -1.0, 0.0, 1.0);\n"
    508 			<< "    out_color        = in_color[0];\n"
    509 			<< "    EmitVertex();"
    510 			<< "\n"
    511 			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
    512 			<< "    gl_Position      = vec4(-1.0, 1.0, 0.0, 1.0);\n"
    513 			<< "    out_color        = in_color[0];\n"
    514 			<< "    EmitVertex();"
    515 			<< "\n"
    516 			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
    517 			<< "    gl_Position      = vec4(1.0, -1.0, 0.0, 1.0);\n"
    518 			<< "    out_color        = in_color[0];\n"
    519 			<< "    EmitVertex();"
    520 			<< "\n"
    521 			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
    522 			<< "    gl_Position      = vec4(1.0, 1.0, 0.0, 1.0);\n"
    523 			<< "    out_color        = in_color[0];\n"
    524 			<< "    EmitVertex();"
    525 			<< "}\n";
    526 
    527 		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
    528 	}
    529 
    530 	// Fragment shader
    531 	{
    532 		std::ostringstream src;
    533 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    534 			<< "\n"
    535 			<< "layout(location = 0) in  vec4 in_color;\n"
    536 			<< "layout(location = 0) out vec4 out_color;\n"
    537 			<< "\n"
    538 			<< "void main(void)\n"
    539 			<< "{\n"
    540 			<< "    out_color = in_color;\n"
    541 			<< "}\n";
    542 
    543 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    544 	}
    545 }
    546 
    547 class ScissorRenderer
    548 {
    549 public:
    550 	ScissorRenderer (Context&					context,
    551 					 const IVec2&				renderSize,
    552 					 const int					numViewports,
    553 					 const std::vector<IVec4>&	scissors,
    554 					 const VkFormat				colorFormat,
    555 					 const Vec4&				clearColor,
    556 					 const std::vector<Vec4>&	vertices)
    557 		: m_renderSize				(renderSize)
    558 		, m_colorFormat				(colorFormat)
    559 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
    560 		, m_clearColor				(clearColor)
    561 		, m_numViewports			(numViewports)
    562 		, m_vertexBufferSize		(sizeInBytes(vertices))
    563 	{
    564 		const DeviceInterface&		vk					= context.getDeviceInterface();
    565 		const VkDevice				device				= context.getDevice();
    566 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
    567 		Allocator&					allocator			= context.getDefaultAllocator();
    568 
    569 		m_colorImage		= makeImage				(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
    570 		m_colorImageAlloc	= bindImage				(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
    571 		m_colorAttachment	= makeImageView			(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
    572 
    573 		m_vertexBuffer		= makeBuffer			(vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
    574 		m_vertexBufferAlloc	= bindBuffer			(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
    575 
    576 		{
    577 			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
    578 			flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
    579 		}
    580 
    581 		m_vertexModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
    582 		m_geometryModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("geom"), 0u);
    583 		m_fragmentModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
    584 		m_renderPass		= makeRenderPass		(vk, device, m_colorFormat);
    585 		m_framebuffer		= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
    586 													 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
    587 		m_pipelineLayout	= makePipelineLayout	(vk, device);
    588 		m_pipeline			= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_geometryModule, *m_fragmentModule,
    589 													 m_renderSize, m_numViewports, scissors);
    590 		m_cmdPool			= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
    591 		m_cmdBuffer			= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
    592 	}
    593 
    594 	void draw (Context& context, const VkBuffer colorBuffer) const
    595 	{
    596 		const DeviceInterface&		vk			= context.getDeviceInterface();
    597 		const VkDevice				device		= context.getDevice();
    598 		const VkQueue				queue		= context.getUniversalQueue();
    599 
    600 		beginCommandBuffer(vk, *m_cmdBuffer);
    601 
    602 		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
    603 		const VkRect2D				renderArea	=
    604 		{
    605 			makeOffset2D(0, 0),
    606 			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
    607 		};
    608 		const VkRenderPassBeginInfo renderPassBeginInfo =
    609 		{
    610 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
    611 			DE_NULL,										// const void*             pNext;
    612 			*m_renderPass,									// VkRenderPass            renderPass;
    613 			*m_framebuffer,									// VkFramebuffer           framebuffer;
    614 			renderArea,										// VkRect2D                renderArea;
    615 			1u,												// uint32_t                clearValueCount;
    616 			&clearValue,									// const VkClearValue*     pClearValues;
    617 		};
    618 		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    619 
    620 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
    621 		{
    622 			const VkDeviceSize vertexBufferOffset = 0ull;
    623 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
    624 		}
    625 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports), 1u, 0u, 0u);	// one vertex per viewport
    626 		vk.cmdEndRenderPass(*m_cmdBuffer);
    627 
    628 		// Prepare color image for copy
    629 		{
    630 			const VkImageMemoryBarrier barriers[] =
    631 			{
    632 				{
    633 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
    634 					DE_NULL,													// const void*				pNext;
    635 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
    636 					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
    637 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
    638 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
    639 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
    640 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
    641 					*m_colorImage,												// VkImage					image;
    642 					m_colorSubresourceRange,									// VkImageSubresourceRange	subresourceRange;
    643 				},
    644 			};
    645 
    646 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
    647 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
    648 		}
    649 		// Color image -> host buffer
    650 		{
    651 			const VkBufferImageCopy region =
    652 			{
    653 				0ull,																		// VkDeviceSize                bufferOffset;
    654 				0u,																			// uint32_t                    bufferRowLength;
    655 				0u,																			// uint32_t                    bufferImageHeight;
    656 				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),			// VkImageSubresourceLayers    imageSubresource;
    657 				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
    658 				makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),						// VkExtent3D                  imageExtent;
    659 			};
    660 
    661 			vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
    662 		}
    663 		// Buffer write barrier
    664 		{
    665 			const VkBufferMemoryBarrier barriers[] =
    666 			{
    667 				{
    668 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
    669 					DE_NULL,										// const void*        pNext;
    670 					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
    671 					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
    672 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
    673 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
    674 					colorBuffer,									// VkBuffer           buffer;
    675 					0ull,											// VkDeviceSize       offset;
    676 					VK_WHOLE_SIZE,									// VkDeviceSize       size;
    677 				},
    678 			};
    679 
    680 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
    681 				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
    682 		}
    683 
    684 		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
    685 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
    686 	}
    687 
    688 private:
    689 	const IVec2						m_renderSize;
    690 	const VkFormat					m_colorFormat;
    691 	const VkImageSubresourceRange	m_colorSubresourceRange;
    692 	const Vec4						m_clearColor;
    693 	const int						m_numViewports;
    694 	const VkDeviceSize				m_vertexBufferSize;
    695 
    696 	Move<VkImage>					m_colorImage;
    697 	MovePtr<Allocation>				m_colorImageAlloc;
    698 	Move<VkImageView>				m_colorAttachment;
    699 	Move<VkBuffer>					m_vertexBuffer;
    700 	MovePtr<Allocation>				m_vertexBufferAlloc;
    701 	Move<VkShaderModule>			m_vertexModule;
    702 	Move<VkShaderModule>			m_geometryModule;
    703 	Move<VkShaderModule>			m_fragmentModule;
    704 	Move<VkRenderPass>				m_renderPass;
    705 	Move<VkFramebuffer>				m_framebuffer;
    706 	Move<VkPipelineLayout>			m_pipelineLayout;
    707 	Move<VkPipeline>				m_pipeline;
    708 	Move<VkCommandPool>				m_cmdPool;
    709 	Move<VkCommandBuffer>			m_cmdBuffer;
    710 
    711 	// "deleted"
    712 						ScissorRenderer	(const ScissorRenderer&);
    713 	ScissorRenderer&	operator=		(const ScissorRenderer&);
    714 };
    715 
    716 tcu::TestStatus test (Context& context, const int numViewports)
    717 {
    718 	requireFeatureMultiViewport(context.getInstanceInterface(), context.getPhysicalDevice());
    719 
    720 	const DeviceInterface&			vk					= context.getDeviceInterface();
    721 	const VkDevice					device				= context.getDevice();
    722 	Allocator&						allocator			= context.getDefaultAllocator();
    723 
    724 	const IVec2						renderSize			(128, 128);
    725 	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
    726 	const Vec4						clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
    727 	const std::vector<Vec4>			vertexColors		= generateColors(numViewports);
    728 	const std::vector<IVec4>		scissors			= generateScissors(numViewports, renderSize);
    729 
    730 	const VkDeviceSize				colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
    731 	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
    732 	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
    733 
    734 	zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize);
    735 
    736 	{
    737 		context.getTestContext().getLog()
    738 			<< tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
    739 			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
    740 	}
    741 
    742 	// Draw
    743 	{
    744 		const ScissorRenderer renderer (context, renderSize, numViewports, scissors, colorFormat, clearColor, vertexColors);
    745 		renderer.draw(context, *colorBuffer);
    746 	}
    747 
    748 	// Log image
    749 	{
    750 		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), 0ull, colorBufferSize);
    751 
    752 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr());
    753 		const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, scissors, vertexColors);
    754 
    755 		// Images should now match.
    756 		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
    757 			return tcu::TestStatus::fail("Rendered image is not correct");
    758 	}
    759 
    760 	return tcu::TestStatus::pass("OK");
    761 }
    762 
    763 } // anonymous
    764 
    765 tcu::TestCaseGroup* createScissorMultiViewportTests	(tcu::TestContext& testCtx)
    766 {
    767 	MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multi_viewport", ""));
    768 
    769 	for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
    770 		addFunctionCaseWithPrograms(group.get(), "scissor_" + de::toString(numViewports), "", initPrograms, test, numViewports);
    771 
    772 	return group.release();
    773 }
    774 
    775 } // FragmentOperations
    776 } // vkt
    777