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 tests
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktFragmentOperationsScissorTests.hpp"
     26 #include "vktFragmentOperationsScissorMultiViewportTests.hpp"
     27 #include "vktTestCaseUtil.hpp"
     28 #include "vktTestGroupUtil.hpp"
     29 #include "vktFragmentOperationsMakeUtil.hpp"
     30 
     31 #include "vkDefs.hpp"
     32 #include "vkRefUtil.hpp"
     33 #include "vkTypeUtil.hpp"
     34 #include "vkMemUtil.hpp"
     35 #include "vkPrograms.hpp"
     36 #include "vkImageUtil.hpp"
     37 
     38 #include "tcuTestLog.hpp"
     39 #include "tcuVector.hpp"
     40 #include "tcuImageCompare.hpp"
     41 
     42 #include "deUniquePtr.hpp"
     43 #include "deRandom.hpp"
     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 //! What primitives will be drawn by the test case.
     61 enum TestPrimitive
     62 {
     63 	TEST_PRIMITIVE_POINTS,			//!< Many points.
     64 	TEST_PRIMITIVE_LINES,			//!< Many short lines.
     65 	TEST_PRIMITIVE_TRIANGLES,		//!< Many small triangles.
     66 	TEST_PRIMITIVE_BIG_LINE,		//!< One line crossing the whole render area.
     67 	TEST_PRIMITIVE_BIG_TRIANGLE,	//!< One triangle covering the whole render area.
     68 };
     69 
     70 struct VertexData
     71 {
     72 	Vec4	position;
     73 	Vec4	color;
     74 };
     75 
     76 //! Parameters used by the test case.
     77 struct CaseDef
     78 {
     79 	Vec4			renderArea;		//!< (ox, oy, w, h), where origin (0,0) is the top-left corner of the viewport. Width and height are in range [0, 1].
     80 	Vec4			scissorArea;	//!< scissored area (ox, oy, w, h)
     81 	TestPrimitive	primitive;
     82 };
     83 
     84 template<typename T>
     85 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
     86 {
     87 	return vec.size() * sizeof(vec[0]);
     88 }
     89 
     90 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
     91 {
     92 	const VkImageCreateInfo imageParams =
     93 	{
     94 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
     95 		DE_NULL,										// const void*				pNext;
     96 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
     97 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
     98 		format,											// VkFormat					format;
     99 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
    100 		1u,												// deUint32					mipLevels;
    101 		1u,												// deUint32					arrayLayers;
    102 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
    103 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
    104 		usage,											// VkImageUsageFlags		usage;
    105 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
    106 		0u,												// deUint32					queueFamilyIndexCount;
    107 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
    108 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
    109 	};
    110 	return imageParams;
    111 }
    112 
    113 //! A single-attachment, single-subpass render pass.
    114 Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
    115 								   const VkDevice			device,
    116 								   const VkFormat			colorFormat)
    117 {
    118 	const VkAttachmentDescription colorAttachmentDescription =
    119 	{
    120 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    121 		colorFormat,										// VkFormat							format;
    122 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    123 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    124 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
    125 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
    126 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    127 		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
    128 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
    129 	};
    130 
    131 	const VkAttachmentReference colorAttachmentRef =
    132 	{
    133 		0u,													// deUint32			attachment;
    134 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
    135 	};
    136 
    137 	const VkSubpassDescription subpassDescription =
    138 	{
    139 		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
    140 		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
    141 		0u,													// deUint32							inputAttachmentCount;
    142 		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
    143 		1u,													// deUint32							colorAttachmentCount;
    144 		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
    145 		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
    146 		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
    147 		0u,													// deUint32							preserveAttachmentCount;
    148 		DE_NULL												// const deUint32*					pPreserveAttachments;
    149 	};
    150 
    151 	const VkRenderPassCreateInfo renderPassInfo =
    152 	{
    153 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
    154 		DE_NULL,											// const void*						pNext;
    155 		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
    156 		1u,													// deUint32							attachmentCount;
    157 		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
    158 		1u,													// deUint32							subpassCount;
    159 		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
    160 		0u,													// deUint32							dependencyCount;
    161 		DE_NULL												// const VkSubpassDependency*		pDependencies;
    162 	};
    163 
    164 	return createRenderPass(vk, device, &renderPassInfo);
    165 }
    166 
    167 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
    168 									   const VkDevice				device,
    169 									   const VkPipelineLayout		pipelineLayout,
    170 									   const VkRenderPass			renderPass,
    171 									   const VkShaderModule			vertexModule,
    172 									   const VkShaderModule			fragmentModule,
    173 									   const IVec2					renderSize,
    174 									   const IVec4					scissorArea,	//!< (ox, oy, w, h)
    175 									   const VkPrimitiveTopology	topology)
    176 {
    177 	const VkVertexInputBindingDescription vertexInputBindingDescription =
    178 	{
    179 		0u,								// uint32_t				binding;
    180 		sizeof(VertexData),				// uint32_t				stride;
    181 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
    182 	};
    183 
    184 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
    185 	{
    186 		{
    187 			0u,									// uint32_t			location;
    188 			0u,									// uint32_t			binding;
    189 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
    190 			0u,									// uint32_t			offset;
    191 		},
    192 		{
    193 			1u,									// uint32_t			location;
    194 			0u,									// uint32_t			binding;
    195 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
    196 			sizeof(Vec4),						// uint32_t			offset;
    197 		},
    198 	};
    199 
    200 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
    201 	{
    202 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
    203 		DE_NULL,														// const void*                                 pNext;
    204 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
    205 		1u,																// uint32_t                                    vertexBindingDescriptionCount;
    206 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    207 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
    208 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
    209 	};
    210 
    211 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
    212 	{
    213 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
    214 		DE_NULL,														// const void*                                 pNext;
    215 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
    216 		topology,														// VkPrimitiveTopology                         topology;
    217 		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
    218 	};
    219 
    220 	const VkViewport viewport = makeViewport(
    221 		0.0f, 0.0f,
    222 		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
    223 		0.0f, 1.0f);
    224 
    225 	const VkRect2D scissor = {
    226 		makeOffset2D(scissorArea.x(), scissorArea.y()),
    227 		makeExtent2D(static_cast<deUint32>(scissorArea.z()), static_cast<deUint32>(scissorArea.w())),
    228 	};
    229 
    230 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
    231 	{
    232 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
    233 		DE_NULL,														// const void*                                 pNext;
    234 		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
    235 		1u,																// uint32_t                                    viewportCount;
    236 		&viewport,														// const VkViewport*                           pViewports;
    237 		1u,																// uint32_t                                    scissorCount;
    238 		&scissor,														// const VkRect2D*                             pScissors;
    239 	};
    240 
    241 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
    242 	{
    243 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
    244 		DE_NULL,														// const void*                              pNext;
    245 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
    246 		VK_FALSE,														// VkBool32                                 depthClampEnable;
    247 		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
    248 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
    249 		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
    250 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
    251 		VK_FALSE,														// VkBool32									depthBiasEnable;
    252 		0.0f,															// float									depthBiasConstantFactor;
    253 		0.0f,															// float									depthBiasClamp;
    254 		0.0f,															// float									depthBiasSlopeFactor;
    255 		1.0f,															// float									lineWidth;
    256 	};
    257 
    258 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
    259 	{
    260 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
    261 		DE_NULL,														// const void*								pNext;
    262 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
    263 		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
    264 		VK_FALSE,														// VkBool32									sampleShadingEnable;
    265 		0.0f,															// float									minSampleShading;
    266 		DE_NULL,														// const VkSampleMask*						pSampleMask;
    267 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
    268 		VK_FALSE														// VkBool32									alphaToOneEnable;
    269 	};
    270 
    271 	const VkStencilOpState stencilOpState = makeStencilOpState(
    272 		VK_STENCIL_OP_KEEP,				// stencil fail
    273 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
    274 		VK_STENCIL_OP_KEEP,				// depth only fail
    275 		VK_COMPARE_OP_ALWAYS,			// compare op
    276 		0u,								// compare mask
    277 		0u,								// write mask
    278 		0u);							// reference
    279 
    280 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
    281 	{
    282 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
    283 		DE_NULL,														// const void*								pNext;
    284 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
    285 		VK_FALSE,														// VkBool32									depthTestEnable;
    286 		VK_FALSE,														// VkBool32									depthWriteEnable;
    287 		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
    288 		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
    289 		VK_FALSE,														// VkBool32									stencilTestEnable;
    290 		stencilOpState,													// VkStencilOpState							front;
    291 		stencilOpState,													// VkStencilOpState							back;
    292 		0.0f,															// float									minDepthBounds;
    293 		1.0f,															// float									maxDepthBounds;
    294 	};
    295 
    296 	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    297 	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
    298 	{
    299 		VK_FALSE,						// VkBool32					blendEnable;
    300 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
    301 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
    302 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
    303 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
    304 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
    305 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
    306 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
    307 	};
    308 
    309 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
    310 	{
    311 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
    312 		DE_NULL,														// const void*									pNext;
    313 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
    314 		VK_FALSE,														// VkBool32										logicOpEnable;
    315 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
    316 		1u,																// deUint32										attachmentCount;
    317 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
    318 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
    319 	};
    320 
    321 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
    322 	{
    323 		{
    324 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
    325 			DE_NULL,													// const void*							pNext;
    326 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
    327 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
    328 			vertexModule,												// VkShaderModule						module;
    329 			"main",														// const char*							pName;
    330 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
    331 		},
    332 		{
    333 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
    334 			DE_NULL,													// const void*							pNext;
    335 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
    336 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
    337 			fragmentModule,												// VkShaderModule						module;
    338 			"main",														// const char*							pName;
    339 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
    340 		}
    341 	};
    342 
    343 	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
    344 	{
    345 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
    346 		DE_NULL,											// const void*										pNext;
    347 		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
    348 		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
    349 		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
    350 		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
    351 		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
    352 		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
    353 		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
    354 		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
    355 		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
    356 		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
    357 		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
    358 		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
    359 		pipelineLayout,										// VkPipelineLayout									layout;
    360 		renderPass,											// VkRenderPass										renderPass;
    361 		0u,													// deUint32											subpass;
    362 		DE_NULL,											// VkPipeline										basePipelineHandle;
    363 		0,													// deInt32											basePipelineIndex;
    364 	};
    365 
    366 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
    367 }
    368 
    369 inline VertexData makeVertex (const float x, const float y, const Vec4& color)
    370 {
    371 	const VertexData data = { Vec4(x, y, 0.0f, 1.0f), color };
    372 	return data;
    373 }
    374 
    375 std::vector<VertexData> genVertices (const TestPrimitive primitive, const Vec4& renderArea, const Vec4& primitiveColor)
    376 {
    377 	std::vector<VertexData> vertices;
    378 	de::Random				rng			(1234);
    379 
    380 	const float	x0		= 2.0f * renderArea.x() - 1.0f;
    381 	const float y0		= 2.0f * renderArea.y() - 1.0f;
    382 	const float	rx		= 2.0f * renderArea.z();
    383 	const float	ry		= 2.0f * renderArea.w();
    384 	const float	size	= 0.2f;
    385 
    386 	switch (primitive)
    387 	{
    388 		case TEST_PRIMITIVE_POINTS:
    389 			for (int i = 0; i < 50; ++i)
    390 			{
    391 				const float x = x0 + rng.getFloat(0.0f, rx);
    392 				const float y = y0 + rng.getFloat(0.0f, ry);
    393 				vertices.push_back(makeVertex(x, y, primitiveColor));
    394 			}
    395 			break;
    396 
    397 		case TEST_PRIMITIVE_LINES:
    398 			for (int i = 0; i < 30; ++i)
    399 			{
    400 				const float x = x0 + rng.getFloat(0.0f, rx - size);
    401 				const float y = y0 + rng.getFloat(0.0f, ry - size);
    402 				vertices.push_back(makeVertex(x,        y,        primitiveColor));
    403 				vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
    404 			}
    405 			break;
    406 
    407 		case TEST_PRIMITIVE_TRIANGLES:
    408 			for (int i = 0; i < 20; ++i)
    409 			{
    410 				const float x = x0 + rng.getFloat(0.0f, rx - size);
    411 				const float y = y0 + rng.getFloat(0.0f, ry - size);
    412 				vertices.push_back(makeVertex(x,             y,        primitiveColor));
    413 				vertices.push_back(makeVertex(x + size/2.0f, y + size, primitiveColor));
    414 				vertices.push_back(makeVertex(x + size,      y,        primitiveColor));
    415 			}
    416 			break;
    417 
    418 		case TEST_PRIMITIVE_BIG_LINE:
    419 			vertices.push_back(makeVertex(x0,      y0,      primitiveColor));
    420 			vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
    421 			break;
    422 
    423 		case TEST_PRIMITIVE_BIG_TRIANGLE:
    424 			vertices.push_back(makeVertex(x0,           y0,      primitiveColor));
    425 			vertices.push_back(makeVertex(x0 + rx/2.0f, y0 + ry, primitiveColor));
    426 			vertices.push_back(makeVertex(x0 + rx,      y0,      primitiveColor));
    427 			break;
    428 	}
    429 
    430 	return vertices;
    431 }
    432 
    433 VkPrimitiveTopology	getTopology (const TestPrimitive primitive)
    434 {
    435 	switch (primitive)
    436 	{
    437 		case TEST_PRIMITIVE_POINTS:			return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
    438 
    439 		case TEST_PRIMITIVE_LINES:
    440 		case TEST_PRIMITIVE_BIG_LINE:		return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
    441 
    442 		case TEST_PRIMITIVE_TRIANGLES:
    443 		case TEST_PRIMITIVE_BIG_TRIANGLE:	return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
    444 
    445 		default:
    446 			DE_ASSERT(0);
    447 			return VK_PRIMITIVE_TOPOLOGY_LAST;
    448 	}
    449 }
    450 
    451 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
    452 {
    453 	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
    454 	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
    455 }
    456 
    457 //! Transform from normalized coords to framebuffer space.
    458 inline IVec4 getAreaRect (const Vec4& area, const int width, const int height)
    459 {
    460 	return IVec4(static_cast<deInt32>(static_cast<float>(width)  * area.x()),
    461 				 static_cast<deInt32>(static_cast<float>(height) * area.y()),
    462 				 static_cast<deInt32>(static_cast<float>(width)  * area.z()),
    463 				 static_cast<deInt32>(static_cast<float>(height) * area.w()));
    464 }
    465 
    466 void applyScissor (tcu::PixelBufferAccess imageAccess, const Vec4& floatScissorArea, const Vec4& clearColor)
    467 {
    468 	const IVec4	scissorRect	(getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
    469 	const int	sx0			= scissorRect.x();
    470 	const int	sx1			= scissorRect.x() + scissorRect.z();
    471 	const int	sy0			= scissorRect.y();
    472 	const int	sy1			= scissorRect.y() + scissorRect.w();
    473 
    474 	for (int y = 0; y < imageAccess.getHeight(); ++y)
    475 	for (int x = 0; x < imageAccess.getWidth(); ++x)
    476 	{
    477 		// Fragments outside fail the scissor test.
    478 		if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
    479 			imageAccess.setPixel(clearColor, x, y);
    480 	}
    481 }
    482 
    483 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
    484 {
    485 	DE_UNREF(caseDef);
    486 
    487 	// Vertex shader
    488 	{
    489 		const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
    490 
    491 		std::ostringstream src;
    492 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    493 			<< "\n"
    494 			<< "layout(location = 0) in  vec4 in_position;\n"
    495 			<< "layout(location = 1) in  vec4 in_color;\n"
    496 			<< "layout(location = 0) out vec4 o_color;\n"
    497 			<< "\n"
    498 			<< "out gl_PerVertex {\n"
    499 			<< "    vec4  gl_Position;\n"
    500 			<< (usePointSize ? "    float gl_PointSize;\n" : "")
    501 			<< "};\n"
    502 			<< "\n"
    503 			<< "void main(void)\n"
    504 			<< "{\n"
    505 			<< "    gl_Position  = in_position;\n"
    506 			<< (usePointSize ? "    gl_PointSize = 1.0;\n" : "")
    507 			<< "    o_color      = in_color;\n"
    508 			<< "}\n";
    509 
    510 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    511 	}
    512 
    513 	// Fragment shader
    514 	{
    515 		std::ostringstream src;
    516 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    517 			<< "\n"
    518 			<< "layout(location = 0) in  vec4 in_color;\n"
    519 			<< "layout(location = 0) out vec4 o_color;\n"
    520 			<< "\n"
    521 			<< "void main(void)\n"
    522 			<< "{\n"
    523 			<< "    o_color = in_color;\n"
    524 			<< "}\n";
    525 
    526 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    527 	}
    528 }
    529 
    530 class ScissorRenderer
    531 {
    532 public:
    533 	ScissorRenderer (Context& context, const CaseDef caseDef, const IVec2& renderSize, const VkFormat colorFormat, const Vec4& primitiveColor, const Vec4& clearColor)
    534 		: m_renderSize				(renderSize)
    535 		, m_colorFormat				(colorFormat)
    536 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
    537 		, m_primitiveColor			(primitiveColor)
    538 		, m_clearColor				(clearColor)
    539 		, m_vertices				(genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
    540 		, m_vertexBufferSize		(sizeInBytes(m_vertices))
    541 		, m_topology				(getTopology(caseDef.primitive))
    542 	{
    543 		const DeviceInterface&		vk					= context.getDeviceInterface();
    544 		const VkDevice				device				= context.getDevice();
    545 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
    546 		Allocator&					allocator			= context.getDefaultAllocator();
    547 
    548 		m_colorImage			= makeImage(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
    549 		m_colorImageAlloc		= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
    550 		m_colorAttachment		= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
    551 
    552 		m_vertexBuffer			= makeBuffer(vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
    553 		m_vertexBufferAlloc		= bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
    554 
    555 		{
    556 			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
    557 			flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
    558 		}
    559 
    560 		m_vertexModule				= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
    561 		m_fragmentModule			= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
    562 		m_renderPass				= makeRenderPass		(vk, device, m_colorFormat);
    563 		m_framebuffer				= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
    564 															 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
    565 		m_pipelineLayout			= makePipelineLayout	(vk, device);
    566 		m_cmdPool					= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
    567 		m_cmdBuffer					= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
    568 
    569 	}
    570 
    571 	void draw (Context& context, const Vec4& scissorAreaFloat, const VkBuffer colorBuffer) const
    572 	{
    573 		const DeviceInterface&		vk			= context.getDeviceInterface();
    574 		const VkDevice				device		= context.getDevice();
    575 		const VkQueue				queue		= context.getUniversalQueue();
    576 
    577 		// New pipeline, because we're modifying scissor (we don't use dynamic state).
    578 		const Unique<VkPipeline>	pipeline	(makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
    579 												 m_renderSize, getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
    580 
    581 		beginCommandBuffer(vk, *m_cmdBuffer);
    582 
    583 		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
    584 		const VkRect2D				renderArea	=
    585 		{
    586 			makeOffset2D(0, 0),
    587 			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
    588 		};
    589 		const VkRenderPassBeginInfo renderPassBeginInfo =
    590 		{
    591 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
    592 			DE_NULL,										// const void*             pNext;
    593 			*m_renderPass,									// VkRenderPass            renderPass;
    594 			*m_framebuffer,									// VkFramebuffer           framebuffer;
    595 			renderArea,										// VkRect2D                renderArea;
    596 			1u,												// uint32_t                clearValueCount;
    597 			&clearValue,									// const VkClearValue*     pClearValues;
    598 		};
    599 		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    600 
    601 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
    602 		{
    603 			const VkDeviceSize vertexBufferOffset = 0ull;
    604 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
    605 		}
    606 
    607 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);
    608 		vk.cmdEndRenderPass(*m_cmdBuffer);
    609 
    610 		// Prepare color image for copy
    611 		{
    612 			const VkImageMemoryBarrier barriers[] =
    613 			{
    614 				{
    615 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
    616 					DE_NULL,													// const void*				pNext;
    617 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
    618 					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
    619 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
    620 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
    621 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
    622 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
    623 					*m_colorImage,												// VkImage					image;
    624 					m_colorSubresourceRange,									// VkImageSubresourceRange	subresourceRange;
    625 				},
    626 			};
    627 
    628 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
    629 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
    630 		}
    631 		// Color image -> host buffer
    632 		{
    633 			const VkBufferImageCopy region =
    634 			{
    635 				0ull,																		// VkDeviceSize                bufferOffset;
    636 				0u,																			// uint32_t                    bufferRowLength;
    637 				0u,																			// uint32_t                    bufferImageHeight;
    638 				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),			// VkImageSubresourceLayers    imageSubresource;
    639 				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
    640 				makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),						// VkExtent3D                  imageExtent;
    641 			};
    642 
    643 			vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
    644 		}
    645 		// Buffer write barrier
    646 		{
    647 			const VkBufferMemoryBarrier barriers[] =
    648 			{
    649 				{
    650 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
    651 					DE_NULL,										// const void*        pNext;
    652 					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
    653 					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
    654 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
    655 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
    656 					colorBuffer,									// VkBuffer           buffer;
    657 					0ull,											// VkDeviceSize       offset;
    658 					VK_WHOLE_SIZE,									// VkDeviceSize       size;
    659 				},
    660 			};
    661 
    662 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
    663 				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
    664 		}
    665 
    666 		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
    667 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
    668 	}
    669 
    670 private:
    671 	const IVec2						m_renderSize;
    672 	const VkFormat					m_colorFormat;
    673 	const VkImageSubresourceRange	m_colorSubresourceRange;
    674 	const Vec4						m_primitiveColor;
    675 	const Vec4						m_clearColor;
    676 	const std::vector<VertexData>	m_vertices;
    677 	const VkDeviceSize				m_vertexBufferSize;
    678 	const VkPrimitiveTopology		m_topology;
    679 
    680 	Move<VkImage>					m_colorImage;
    681 	MovePtr<Allocation>				m_colorImageAlloc;
    682 	Move<VkImageView>				m_colorAttachment;
    683 	Move<VkBuffer>					m_vertexBuffer;
    684 	MovePtr<Allocation>				m_vertexBufferAlloc;
    685 	Move<VkShaderModule>			m_vertexModule;
    686 	Move<VkShaderModule>			m_fragmentModule;
    687 	Move<VkRenderPass>				m_renderPass;
    688 	Move<VkFramebuffer>				m_framebuffer;
    689 	Move<VkPipelineLayout>			m_pipelineLayout;
    690 	Move<VkCommandPool>				m_cmdPool;
    691 	Move<VkCommandBuffer>			m_cmdBuffer;
    692 
    693 	// "deleted"
    694 						ScissorRenderer	(const ScissorRenderer&);
    695 	ScissorRenderer&	operator=		(const ScissorRenderer&);
    696 };
    697 
    698 tcu::TestStatus test (Context& context, const CaseDef caseDef)
    699 {
    700 	const DeviceInterface&			vk							= context.getDeviceInterface();
    701 	const VkDevice					device						= context.getDevice();
    702 	Allocator&						allocator					= context.getDefaultAllocator();
    703 
    704 	const IVec2						renderSize					(128, 128);
    705 	const VkFormat					colorFormat					= VK_FORMAT_R8G8B8A8_UNORM;
    706 	const Vec4						scissorFullArea				(0.0f, 0.0f, 1.0f, 1.0f);
    707 	const Vec4						primitiveColor				(1.0f, 1.0f, 1.0f, 1.0f);
    708 	const Vec4						clearColor					(0.5f, 0.5f, 1.0f, 1.0f);
    709 
    710 	const VkDeviceSize				colorBufferSize				= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
    711 	const Unique<VkBuffer>			colorBufferFull				(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
    712 	const UniquePtr<Allocation>		colorBufferFullAlloc		(bindBuffer(vk, device, allocator, *colorBufferFull, MemoryRequirement::HostVisible));
    713 
    714 	const Unique<VkBuffer>			colorBufferScissored		(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
    715 	const UniquePtr<Allocation>		colorBufferScissoredAlloc	(bindBuffer(vk, device, allocator, *colorBufferScissored, MemoryRequirement::HostVisible));
    716 
    717 	zeroBuffer(vk, device, *colorBufferFullAlloc, colorBufferSize);
    718 	zeroBuffer(vk, device, *colorBufferScissoredAlloc, colorBufferSize);
    719 
    720 	// Draw
    721 	{
    722 		const ScissorRenderer renderer (context, caseDef, renderSize, colorFormat, primitiveColor, clearColor);
    723 
    724 		renderer.draw(context, scissorFullArea, *colorBufferFull);
    725 		renderer.draw(context, caseDef.scissorArea, *colorBufferScissored);
    726 	}
    727 
    728 	// Log image
    729 	{
    730 		invalidateMappedMemoryRange(vk, device, colorBufferFullAlloc->getMemory(), 0ull, colorBufferSize);
    731 		invalidateMappedMemoryRange(vk, device, colorBufferScissoredAlloc->getMemory(), 0ull, colorBufferSize);
    732 
    733 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferScissoredAlloc->getHostPtr());
    734 		tcu::PixelBufferAccess				referenceImage	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferFullAlloc->getHostPtr());
    735 
    736 		// Apply scissor to the full image, so we can compare it with the result image.
    737 		applyScissor (referenceImage, caseDef.scissorArea, clearColor);
    738 
    739 		// Images should now match.
    740 		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage, resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
    741 			return tcu::TestStatus::fail("Rendered image is not correct");
    742 	}
    743 
    744 	return tcu::TestStatus::pass("OK");
    745 }
    746 
    747 //! \note The ES 2.0 scissoring tests included color/depth/stencil clear cases, but these operations are not affected by scissor test in Vulkan.
    748 //!       Scissor is part of the pipeline state and pipeline only affects the drawing commands.
    749 void createTestsInGroup (tcu::TestCaseGroup* scissorGroup)
    750 {
    751 	tcu::TestContext& testCtx = scissorGroup->getTestContext();
    752 
    753 	struct TestSpec
    754 	{
    755 		const char*		name;
    756 		const char*		description;
    757 		CaseDef			caseDef;
    758 	};
    759 
    760 	const Vec4	areaFull			(0.0f, 0.0f, 1.0f, 1.0f);
    761 	const Vec4	areaCropped			(0.2f, 0.2f, 0.6f, 0.6f);
    762 	const Vec4	areaCroppedMore		(0.4f, 0.4f, 0.2f, 0.2f);
    763 	const Vec4	areaLeftHalf		(0.0f, 0.0f, 0.5f, 1.0f);
    764 	const Vec4	areaRightHalf		(0.5f, 0.0f, 0.5f, 1.0f);
    765 
    766 	// Points
    767 	{
    768 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "points", ""));
    769 
    770 		const TestSpec	cases[] =
    771 		{
    772 			{ "inside",				"Points fully inside the scissor area",		{ areaFull,		areaFull,		TEST_PRIMITIVE_POINTS } },
    773 			{ "partially_inside",	"Points partially inside the scissor area",	{ areaFull,		areaCropped,	TEST_PRIMITIVE_POINTS } },
    774 			{ "outside",			"Points fully outside the scissor area",	{ areaLeftHalf,	areaRightHalf,	TEST_PRIMITIVE_POINTS } },
    775 		};
    776 
    777 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
    778 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
    779 
    780 		scissorGroup->addChild(primitiveGroup.release());
    781 	}
    782 
    783 	// Lines
    784 	{
    785 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "lines", ""));
    786 
    787 		const TestSpec	cases[] =
    788 		{
    789 			{ "inside",				"Lines fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_LINES	} },
    790 			{ "partially_inside",	"Lines partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_LINES	} },
    791 			{ "outside",			"Lines fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_LINES	} },
    792 			{ "crossing",			"A line crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_LINE	} },
    793 		};
    794 
    795 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
    796 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
    797 
    798 		scissorGroup->addChild(primitiveGroup.release());
    799 	}
    800 
    801 	// Triangles
    802 	{
    803 		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "triangles", ""));
    804 
    805 		const TestSpec	cases[] =
    806 		{
    807 			{ "inside",				"Triangles fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_TRIANGLES	} },
    808 			{ "partially_inside",	"Triangles partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_TRIANGLES	} },
    809 			{ "outside",			"Triangles fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_TRIANGLES	} },
    810 			{ "crossing",			"A triangle crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_TRIANGLE	} },
    811 		};
    812 
    813 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
    814 			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
    815 
    816 		scissorGroup->addChild(primitiveGroup.release());
    817 	}
    818 
    819 	// Mulit-viewport scissor
    820 	{
    821 		scissorGroup->addChild(createScissorMultiViewportTests(testCtx));
    822 	}
    823 }
    824 
    825 } // anonymous
    826 
    827 tcu::TestCaseGroup* createScissorTests (tcu::TestContext& testCtx)
    828 {
    829 	return createTestGroup(testCtx, "scissor", "Scissor tests", createTestsInGroup);
    830 }
    831 
    832 } // FragmentOperations
    833 } // vkt
    834