Home | History | Annotate | Download | only in clipping
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2016 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
     21  * \brief Clipping tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktClippingTests.hpp"
     25 #include "vktTestCase.hpp"
     26 #include "vktTestGroupUtil.hpp"
     27 #include "vktTestCaseUtil.hpp"
     28 #include "vktClippingUtil.hpp"
     29 #include "vkRefUtil.hpp"
     30 #include "vkTypeUtil.hpp"
     31 #include "vkImageUtil.hpp"
     32 #include "deUniquePtr.hpp"
     33 #include "deStringUtil.hpp"
     34 #include "deRandom.hpp"
     35 
     36 namespace vkt
     37 {
     38 namespace clipping
     39 {
     40 namespace
     41 {
     42 using namespace vk;
     43 using de::MovePtr;
     44 using tcu::UVec2;
     45 using tcu::Vec4;
     46 using tcu::IVec2;
     47 
     48 enum Constants
     49 {
     50 	RENDER_SIZE								= 16,
     51 	RENDER_SIZE_LARGE						= 128,
     52 	NUM_RENDER_PIXELS						= RENDER_SIZE * RENDER_SIZE,
     53 	NUM_PATCH_CONTROL_POINTS				= 3,
     54 	MAX_NUM_SHADER_MODULES					= 5,
     55 	MAX_CLIP_DISTANCES						= 8,
     56 	MAX_CULL_DISTANCES						= 8,
     57 	MAX_COMBINED_CLIP_AND_CULL_DISTANCES	= 8,
     58 };
     59 
     60 struct Shader
     61 {
     62 	VkShaderStageFlagBits	stage;
     63 	const ProgramBinary*	binary;
     64 
     65 	Shader (const VkShaderStageFlagBits stage_, const ProgramBinary& binary_)
     66 		: stage		(stage_)
     67 		, binary	(&binary_)
     68 	{
     69 	}
     70 };
     71 
     72 //! Sets up a graphics pipeline and enables simple draw calls to predefined attachments.
     73 //! Clip volume uses wc = 1.0, which gives clip coord ranges: x = [-1, 1], y = [-1, 1], z = [0, 1]
     74 //! Clip coords (-1,-1) map to viewport coords (0, 0).
     75 class DrawContext
     76 {
     77 public:
     78 									DrawContext		(Context&						context,
     79 													 const std::vector<Shader>&		shaders,
     80 													 const std::vector<Vec4>&		vertices,
     81 													 const VkPrimitiveTopology		primitiveTopology,
     82 													 const deUint32					renderSize			= static_cast<deUint32>(RENDER_SIZE),
     83 													 const bool						depthClampEnable	= false,
     84 													 const bool						blendEnable			= false,
     85 													 const float					lineWidth			= 1.0f);
     86 
     87 	void							draw			(void);
     88 	tcu::ConstPixelBufferAccess		getColorPixels	(void) const;
     89 
     90 private:
     91 	Context&						m_context;
     92 	const VkFormat					m_colorFormat;
     93 	const VkImageSubresourceRange	m_colorSubresourceRange;
     94 	const UVec2						m_renderSize;
     95 	const VkExtent3D				m_imageExtent;
     96 	const VkPrimitiveTopology		m_primitiveTopology;
     97 	const bool						m_depthClampEnable;
     98 	const bool						m_blendEnable;
     99 	const deUint32					m_numVertices;
    100 	const float						m_lineWidth;
    101 	const deUint32					m_numPatchControlPoints;
    102 	MovePtr<Buffer>					m_vertexBuffer;
    103 	MovePtr<Image>					m_colorImage;
    104 	MovePtr<Buffer>					m_colorAttachmentBuffer;
    105 	Move<VkImageView>				m_colorImageView;
    106 	Move<VkRenderPass>				m_renderPass;
    107 	Move<VkFramebuffer>				m_framebuffer;
    108 	Move<VkPipelineLayout>			m_pipelineLayout;
    109 	Move<VkPipeline>				m_pipeline;
    110 	Move<VkCommandPool>				m_cmdPool;
    111 	Move<VkCommandBuffer>			m_cmdBuffer;
    112 	Move<VkShaderModule>			m_shaderModules[MAX_NUM_SHADER_MODULES];
    113 
    114 									DrawContext		(const DrawContext&);	// "deleted"
    115 	DrawContext&					operator=		(const DrawContext&);	// "deleted"
    116 };
    117 
    118 DrawContext::DrawContext (Context&						context,
    119 						  const std::vector<Shader>&	shaders,
    120 						  const std::vector<Vec4>&		vertices,
    121 						  const VkPrimitiveTopology		primitiveTopology,
    122 						  const deUint32				renderSize,
    123 						  const bool					depthClampEnable,
    124 						  const bool					blendEnable,
    125 						  const float					lineWidth)
    126 	: m_context					(context)
    127 	, m_colorFormat				(VK_FORMAT_R8G8B8A8_UNORM)
    128 	, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
    129 	, m_renderSize				(renderSize, renderSize)
    130 	, m_imageExtent				(makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u))
    131 	, m_primitiveTopology		(primitiveTopology)
    132 	, m_depthClampEnable		(depthClampEnable)
    133 	, m_blendEnable				(blendEnable)
    134 	, m_numVertices				(static_cast<deUint32>(vertices.size()))
    135 	, m_lineWidth				(lineWidth)
    136 	, m_numPatchControlPoints	(NUM_PATCH_CONTROL_POINTS)		// we're treating patches as triangles
    137 {
    138 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
    139 	const VkDevice			device		= m_context.getDevice();
    140 	Allocator&				allocator	= m_context.getDefaultAllocator();
    141 
    142 	// Command buffer
    143 	{
    144 		m_cmdPool	= makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex());
    145 		m_cmdBuffer	= makeCommandBuffer(vk, device, *m_cmdPool);
    146 	}
    147 
    148 	// Color attachment image
    149 	{
    150 		const VkImageUsageFlags usage			= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    151 		const VkImageCreateInfo	imageCreateInfo	=
    152 		{
    153 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType          sType;
    154 			DE_NULL,									// const void*              pNext;
    155 			(VkImageCreateFlags)0,						// VkImageCreateFlags       flags;
    156 			VK_IMAGE_TYPE_2D,							// VkImageType              imageType;
    157 			m_colorFormat,								// VkFormat                 format;
    158 			m_imageExtent,								// VkExtent3D               extent;
    159 			1u,											// uint32_t                 mipLevels;
    160 			1u,											// uint32_t                 arrayLayers;
    161 			VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits    samples;
    162 			VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling            tiling;
    163 			usage,										// VkImageUsageFlags        usage;
    164 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode            sharingMode;
    165 			VK_QUEUE_FAMILY_IGNORED,					// uint32_t                 queueFamilyIndexCount;
    166 			DE_NULL,									// const uint32_t*          pQueueFamilyIndices;
    167 			VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout            initialLayout;
    168 		};
    169 
    170 		m_colorImage = MovePtr<Image>(new Image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any));
    171 		m_colorImageView = makeImageView(vk, device, **m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
    172 
    173 		// Buffer to copy attachment data after rendering
    174 
    175 		const VkDeviceSize bitmapSize = tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_renderSize.x() * m_renderSize.y();
    176 		m_colorAttachmentBuffer = MovePtr<Buffer>(new Buffer(
    177 			vk, device, allocator, makeBufferCreateInfo(bitmapSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible));
    178 
    179 		{
    180 			const Allocation& alloc = m_colorAttachmentBuffer->getAllocation();
    181 			deMemset(alloc.getHostPtr(), 0, (size_t)bitmapSize);
    182 			flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bitmapSize);
    183 		}
    184 	}
    185 
    186 	// Vertex buffer
    187 	{
    188 		const VkDeviceSize bufferSize = vertices.size() * sizeof(vertices[0]);
    189 		m_vertexBuffer = MovePtr<Buffer>(new Buffer(
    190 			vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
    191 
    192 		const Allocation& alloc = m_vertexBuffer->getAllocation();
    193 		deMemcpy(alloc.getHostPtr(), &vertices[0], (size_t)bufferSize);
    194 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize);
    195 	}
    196 
    197 	// Pipeline layout
    198 	{
    199 		m_pipelineLayout = makePipelineLayoutWithoutDescriptors(vk, device);
    200 	}
    201 
    202 	// Renderpass
    203 	{
    204 		const VkAttachmentDescription colorAttachmentDescription =
    205 		{
    206 			(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    207 			m_colorFormat,										// VkFormat							format;
    208 			VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    209 			VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    210 			VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
    211 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
    212 			VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    213 			VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
    214 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
    215 		};
    216 
    217 		const VkAttachmentReference colorAttachmentReference =
    218 		{
    219 			0u,													// deUint32			attachment;
    220 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
    221 		};
    222 
    223 		const VkAttachmentReference depthAttachmentReference =
    224 		{
    225 			VK_ATTACHMENT_UNUSED,								// deUint32			attachment;
    226 			VK_IMAGE_LAYOUT_UNDEFINED							// VkImageLayout	layout;
    227 		};
    228 
    229 		const VkSubpassDescription subpassDescription =
    230 		{
    231 			(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
    232 			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
    233 			0u,													// deUint32							inputAttachmentCount;
    234 			DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
    235 			1u,													// deUint32							colorAttachmentCount;
    236 			&colorAttachmentReference,							// const VkAttachmentReference*		pColorAttachments;
    237 			DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
    238 			&depthAttachmentReference,							// const VkAttachmentReference*		pDepthStencilAttachment;
    239 			0u,													// deUint32							preserveAttachmentCount;
    240 			DE_NULL												// const deUint32*					pPreserveAttachments;
    241 		};
    242 
    243 		const VkRenderPassCreateInfo renderPassInfo =
    244 		{
    245 			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
    246 			DE_NULL,											// const void*						pNext;
    247 			(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
    248 			1u,													// deUint32							attachmentCount;
    249 			&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
    250 			1u,													// deUint32							subpassCount;
    251 			&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
    252 			0u,													// deUint32							dependencyCount;
    253 			DE_NULL												// const VkSubpassDependency*		pDependencies;
    254 		};
    255 
    256 		m_renderPass = createRenderPass(vk, device, &renderPassInfo);
    257 	}
    258 
    259 	// Framebuffer
    260 	{
    261 		const VkFramebufferCreateInfo framebufferInfo = {
    262 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
    263 			DE_NULL,										// const void*                                 pNext;
    264 			(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
    265 			*m_renderPass,									// VkRenderPass                                renderPass;
    266 			1u,												// uint32_t                                    attachmentCount;
    267 			&m_colorImageView.get(),						// const VkImageView*                          pAttachments;
    268 			m_renderSize.x(),								// uint32_t                                    width;
    269 			m_renderSize.y(),								// uint32_t                                    height;
    270 			1u,												// uint32_t                                    layers;
    271 		};
    272 
    273 		m_framebuffer = createFramebuffer(vk, device, &framebufferInfo);
    274 	}
    275 
    276 	// Graphics pipeline
    277 	{
    278 		const deUint32	vertexStride	= sizeof(Vec4);
    279 		const VkFormat	vertexFormat	= VK_FORMAT_R32G32B32A32_SFLOAT;
    280 
    281 		const VkVertexInputBindingDescription bindingDesc =
    282 		{
    283 			0u,									// uint32_t				binding;
    284 			vertexStride,						// uint32_t				stride;
    285 			VK_VERTEX_INPUT_RATE_VERTEX,		// VkVertexInputRate	inputRate;
    286 		};
    287 		const VkVertexInputAttributeDescription attributeDesc =
    288 		{
    289 			0u,									// uint32_t			location;
    290 			0u,									// uint32_t			binding;
    291 			vertexFormat,						// VkFormat			format;
    292 			0u,									// uint32_t			offset;
    293 		};
    294 
    295 		const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
    296 		{
    297 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
    298 			DE_NULL,														// const void*                                 pNext;
    299 			(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
    300 			1u,																// uint32_t                                    vertexBindingDescriptionCount;
    301 			&bindingDesc,													// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    302 			1u,																// uint32_t                                    vertexAttributeDescriptionCount;
    303 			&attributeDesc,													// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
    304 		};
    305 
    306 		const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
    307 		{
    308 			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
    309 			DE_NULL,														// const void*                                 pNext;
    310 			(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
    311 			m_primitiveTopology,											// VkPrimitiveTopology                         topology;
    312 			VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
    313 		};
    314 
    315 		const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
    316 		{
    317 			VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType                             sType;
    318 			DE_NULL,														// const void*                                 pNext;
    319 			(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags      flags;
    320 			m_numPatchControlPoints,										// uint32_t                                    patchControlPoints;
    321 		};
    322 
    323 		const VkViewport viewport = makeViewport(
    324 			0.0f, 0.0f,
    325 			static_cast<float>(m_renderSize.x()), static_cast<float>(m_renderSize.y()),
    326 			0.0f, 1.0f);
    327 
    328 		const VkRect2D scissor = {
    329 			makeOffset2D(0, 0),
    330 			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
    331 		};
    332 
    333 		const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
    334 		{
    335 			VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType                             sType;
    336 			DE_NULL,												// const void*                                 pNext;
    337 			(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags          flags;
    338 			1u,														// uint32_t                                    viewportCount;
    339 			&viewport,												// const VkViewport*                           pViewports;
    340 			1u,														// uint32_t                                    scissorCount;
    341 			&scissor,												// const VkRect2D*                             pScissors;
    342 		};
    343 
    344 		const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
    345 		{
    346 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
    347 			DE_NULL,														// const void*                              pNext;
    348 			(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
    349 			m_depthClampEnable,												// VkBool32                                 depthClampEnable;
    350 			VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
    351 			VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
    352 			VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
    353 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
    354 			VK_FALSE,														// VkBool32									depthBiasEnable;
    355 			0.0f,															// float									depthBiasConstantFactor;
    356 			0.0f,															// float									depthBiasClamp;
    357 			0.0f,															// float									depthBiasSlopeFactor;
    358 			m_lineWidth,													// float									lineWidth;
    359 		};
    360 
    361 		const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
    362 		{
    363 			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
    364 			DE_NULL,													// const void*								pNext;
    365 			(VkPipelineMultisampleStateCreateFlags)0,					// VkPipelineMultisampleStateCreateFlags	flags;
    366 			VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits					rasterizationSamples;
    367 			VK_FALSE,													// VkBool32									sampleShadingEnable;
    368 			0.0f,														// float									minSampleShading;
    369 			DE_NULL,													// const VkSampleMask*						pSampleMask;
    370 			VK_FALSE,													// VkBool32									alphaToCoverageEnable;
    371 			VK_FALSE													// VkBool32									alphaToOneEnable;
    372 		};
    373 
    374 		const VkStencilOpState stencilOpState = makeStencilOpState(
    375 			VK_STENCIL_OP_KEEP,		// stencil fail
    376 			VK_STENCIL_OP_KEEP,		// depth & stencil pass
    377 			VK_STENCIL_OP_KEEP,		// depth only fail
    378 			VK_COMPARE_OP_NEVER,	// compare op
    379 			0u,						// compare mask
    380 			0u,						// write mask
    381 			0u);					// reference
    382 
    383 		const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
    384 		{
    385 			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
    386 			DE_NULL,													// const void*								pNext;
    387 			(VkPipelineDepthStencilStateCreateFlags)0,					// VkPipelineDepthStencilStateCreateFlags	flags;
    388 			VK_FALSE,													// VkBool32									depthTestEnable;
    389 			VK_FALSE,													// VkBool32									depthWriteEnable;
    390 			VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
    391 			VK_FALSE,													// VkBool32									depthBoundsTestEnable;
    392 			VK_FALSE,													// VkBool32									stencilTestEnable;
    393 			stencilOpState,												// VkStencilOpState							front;
    394 			stencilOpState,												// VkStencilOpState							back;
    395 			0.0f,														// float									minDepthBounds;
    396 			1.0f,														// float									maxDepthBounds;
    397 		};
    398 
    399 		const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    400 		const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
    401 		{
    402 			m_blendEnable,						// VkBool32					blendEnable;
    403 			VK_BLEND_FACTOR_SRC_ALPHA,			// VkBlendFactor			srcColorBlendFactor;
    404 			VK_BLEND_FACTOR_ONE,				// VkBlendFactor			dstColorBlendFactor;
    405 			VK_BLEND_OP_ADD,					// VkBlendOp				colorBlendOp;
    406 			VK_BLEND_FACTOR_SRC_ALPHA,			// VkBlendFactor			srcAlphaBlendFactor;
    407 			VK_BLEND_FACTOR_ONE,				// VkBlendFactor			dstAlphaBlendFactor;
    408 			VK_BLEND_OP_ADD,					// VkBlendOp				alphaBlendOp;
    409 			colorComponentsAll,					// VkColorComponentFlags	colorWriteMask;
    410 		};
    411 
    412 		const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
    413 		{
    414 			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
    415 			DE_NULL,													// const void*									pNext;
    416 			(VkPipelineColorBlendStateCreateFlags)0,					// VkPipelineColorBlendStateCreateFlags			flags;
    417 			VK_FALSE,													// VkBool32										logicOpEnable;
    418 			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
    419 			1u,															// deUint32										attachmentCount;
    420 			&pipelineColorBlendAttachmentState,							// const VkPipelineColorBlendAttachmentState*	pAttachments;
    421 			{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConstants[4];
    422 		};
    423 
    424 		// Create shader stages
    425 
    426 		std::vector<VkPipelineShaderStageCreateInfo>	shaderStages;
    427 		VkShaderStageFlags								stageFlags = (VkShaderStageFlags)0;
    428 
    429 		DE_ASSERT(shaders.size() <= MAX_NUM_SHADER_MODULES);
    430 		for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx)
    431 		{
    432 			m_shaderModules[shaderNdx] = createShaderModule(vk, device, *shaders[shaderNdx].binary, (VkShaderModuleCreateFlags)0);
    433 
    434 			const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo =
    435 			{
    436 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
    437 				DE_NULL,												// const void*							pNext;
    438 				(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
    439 				shaders[shaderNdx].stage,								// VkShaderStageFlagBits				stage;
    440 				*m_shaderModules[shaderNdx],							// VkShaderModule						module;
    441 				"main",													// const char*							pName;
    442 				DE_NULL,												// const VkSpecializationInfo*			pSpecializationInfo;
    443 			};
    444 
    445 			shaderStages.push_back(pipelineShaderStageInfo);
    446 			stageFlags |= shaders[shaderNdx].stage;
    447 		}
    448 
    449 		DE_ASSERT(
    450 			(m_primitiveTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) ||
    451 			(stageFlags & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)));
    452 
    453 		const bool tessellationEnabled = (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
    454 		const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
    455 		{
    456 			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,						// VkStructureType									sType;
    457 			DE_NULL,																// const void*										pNext;
    458 			(VkPipelineCreateFlags)0,												// VkPipelineCreateFlags							flags;
    459 			static_cast<deUint32>(shaderStages.size()),								// deUint32											stageCount;
    460 			&shaderStages[0],														// const VkPipelineShaderStageCreateInfo*			pStages;
    461 			&vertexInputStateInfo,													// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
    462 			&pipelineInputAssemblyStateInfo,										// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
    463 			(tessellationEnabled ? &pipelineTessellationStateInfo : DE_NULL),		// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
    464 			&pipelineViewportStateInfo,												// const VkPipelineViewportStateCreateInfo*			pViewportState;
    465 			&pipelineRasterizationStateInfo,										// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
    466 			&pipelineMultisampleStateInfo,											// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
    467 			&pipelineDepthStencilStateInfo,											// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
    468 			&pipelineColorBlendStateInfo,											// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
    469 			DE_NULL,																// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
    470 			*m_pipelineLayout,														// VkPipelineLayout									layout;
    471 			*m_renderPass,															// VkRenderPass										renderPass;
    472 			0u,																		// deUint32											subpass;
    473 			DE_NULL,																// VkPipeline										basePipelineHandle;
    474 			0,																		// deInt32											basePipelineIndex;
    475 		};
    476 
    477 		m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
    478 	}
    479 
    480 	// Record commands
    481 	{
    482 		const VkDeviceSize zeroOffset = 0ull;
    483 
    484 		beginCommandBuffer(vk, *m_cmdBuffer);
    485 
    486 		// Begin render pass
    487 		{
    488 			const VkClearValue	clearValue = makeClearValueColor(Vec4(0.0f, 0.0f, 0.0f, 1.0f));
    489 			const VkRect2D		renderArea =
    490 			{
    491 				makeOffset2D(0, 0),
    492 				makeExtent2D(m_renderSize.x(), m_renderSize.y())
    493 			};
    494 
    495 			const VkRenderPassBeginInfo renderPassBeginInfo = {
    496 				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
    497 				DE_NULL,										// const void*             pNext;
    498 				*m_renderPass,									// VkRenderPass            renderPass;
    499 				*m_framebuffer,									// VkFramebuffer           framebuffer;
    500 				renderArea,										// VkRect2D                renderArea;
    501 				1u,												// uint32_t                clearValueCount;
    502 				&clearValue,									// const VkClearValue*     pClearValues;
    503 			};
    504 
    505 			vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    506 		}
    507 
    508 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
    509 		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &(**m_vertexBuffer), &zeroOffset);
    510 
    511 		vk.cmdDraw(*m_cmdBuffer, m_numVertices, 1u, 0u, 1u);
    512 		vk.cmdEndRenderPass(*m_cmdBuffer);
    513 
    514 		// Barrier: draw -> copy from image
    515 		{
    516 			const VkImageMemoryBarrier barrier = makeImageMemoryBarrier(
    517 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
    518 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
    519 				**m_colorImage, m_colorSubresourceRange);
    520 
    521 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0,
    522 				0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
    523 		}
    524 
    525 		{
    526 			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), m_imageExtent);
    527 			vk.cmdCopyImageToBuffer(*m_cmdBuffer, **m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_colorAttachmentBuffer, 1u, &copyRegion);
    528 		}
    529 
    530 		// Barrier: copy to buffer -> host read
    531 		{
    532 			const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier(
    533 				VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
    534 				**m_colorAttachmentBuffer, 0ull, VK_WHOLE_SIZE);
    535 
    536 			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
    537 				0u, DE_NULL, 1u, &barrier, 0u, DE_NULL);
    538 		}
    539 
    540 		endCommandBuffer(vk, *m_cmdBuffer);
    541 	}
    542 }
    543 
    544 void DrawContext::draw (void)
    545 {
    546 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
    547 	const VkDevice			device		= m_context.getDevice();
    548 	const VkQueue			queue		= m_context.getUniversalQueue();
    549 	tcu::TestLog&			log			= m_context.getTestContext().getLog();
    550 
    551 	submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
    552 
    553 	log << tcu::LogImageSet("attachments", "") << tcu::LogImage("color0", "", getColorPixels()) << tcu::TestLog::EndImageSet;
    554 }
    555 
    556 tcu::ConstPixelBufferAccess DrawContext::getColorPixels (void) const
    557 {
    558 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
    559 	const VkDevice			device		= m_context.getDevice();
    560 
    561 	const Allocation& alloc = m_colorAttachmentBuffer->getAllocation();
    562 	invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
    563 
    564 	return tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), m_imageExtent.width, m_imageExtent.height, m_imageExtent.depth, alloc.getHostPtr());
    565 }
    566 
    567 std::vector<Vec4> genVertices (const VkPrimitiveTopology topology, const Vec4& offset, const float slope)
    568 {
    569 	const float p  = 1.0f;
    570 	const float hp = 0.5f;
    571 	const float z  = 0.0f;
    572 	const float w  = 1.0f;
    573 
    574 	std::vector<Vec4> vertices;
    575 
    576 	// We're setting adjacent vertices to zero where needed, as we don't use them in meaningful way.
    577 
    578 	switch (topology)
    579 	{
    580 		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
    581 			vertices.push_back(offset + Vec4(0.0f, 0.0f, slope/2.0f + z, w));
    582 			vertices.push_back(offset + Vec4( -hp,  -hp,              z, w));
    583 			vertices.push_back(offset + Vec4(  hp,  -hp,      slope + z, w));
    584 			vertices.push_back(offset + Vec4( -hp,   hp,              z, w));
    585 			vertices.push_back(offset + Vec4(  hp,   hp,      slope + z, w));
    586 			break;
    587 
    588 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
    589 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    590 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// line 0
    591 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));
    592 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// line 1
    593 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));
    594 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// line 2
    595 			break;
    596 
    597 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
    598 			vertices.push_back(Vec4());
    599 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    600 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// line 0
    601 			vertices.push_back(Vec4());
    602 			vertices.push_back(Vec4());
    603 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));
    604 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// line 1
    605 			vertices.push_back(Vec4());
    606 			vertices.push_back(Vec4());
    607 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));
    608 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// line 2
    609 			vertices.push_back(Vec4());
    610 			break;
    611 
    612 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
    613 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    614 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// line 0
    615 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// line 1
    616 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// line 2
    617 			break;
    618 
    619 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
    620 			vertices.push_back(Vec4());
    621 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    622 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// line 0
    623 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// line 1
    624 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// line 2
    625 			vertices.push_back(Vec4());
    626 			break;
    627 
    628 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
    629 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));
    630 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    631 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// triangle 0
    632 			vertices.push_back(offset + Vec4(-p,  p,         z, w));
    633 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));
    634 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// triangle 1
    635 			break;
    636 
    637 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
    638 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));
    639 			vertices.push_back(Vec4());
    640 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    641 			vertices.push_back(Vec4());
    642 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// triangle 0
    643 			vertices.push_back(Vec4());
    644 			vertices.push_back(offset + Vec4(-p,  p,         z, w));
    645 			vertices.push_back(Vec4());
    646 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));
    647 			vertices.push_back(Vec4());
    648 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// triangle 1
    649 			vertices.push_back(Vec4());
    650 			break;
    651 
    652 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
    653 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    654 			vertices.push_back(offset + Vec4(-p,  p,         z, w));
    655 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// triangle 0
    656 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// triangle 1
    657 			break;
    658 
    659 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
    660 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    661 			vertices.push_back(Vec4());
    662 			vertices.push_back(offset + Vec4(-p,  p,         z, w));
    663 			vertices.push_back(Vec4());
    664 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));	// triangle 0
    665 			vertices.push_back(Vec4());
    666 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// triangle 1
    667 			vertices.push_back(Vec4());
    668 			break;
    669 
    670 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
    671 			vertices.push_back(offset + Vec4( p, -p, slope + z, w));
    672 			vertices.push_back(offset + Vec4(-p, -p,         z, w));
    673 			vertices.push_back(offset + Vec4(-p,  p,         z, w));	// triangle 0
    674 			vertices.push_back(offset + Vec4( p,  p, slope + z, w));	// triangle 1
    675 			break;
    676 
    677 		case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
    678 			DE_ASSERT(0);
    679 			break;
    680 
    681 		default:
    682 			DE_ASSERT(0);
    683 			break;
    684 	}
    685 	return vertices;
    686 }
    687 
    688 bool inline isColorInRange (const Vec4& color, const Vec4& minColor, const Vec4& maxColor)
    689 {
    690 	return (minColor.x() <= color.x() && color.x() <= maxColor.x())
    691 		&& (minColor.y() <= color.y() && color.y() <= maxColor.y())
    692 		&& (minColor.z() <= color.z() && color.z() <= maxColor.z())
    693 		&& (minColor.w() <= color.w() && color.w() <= maxColor.w());
    694 }
    695 
    696 //! Count pixels that match color within threshold, in the specified region.
    697 int countPixels (const tcu::ConstPixelBufferAccess pixels, const IVec2& regionOffset, const IVec2& regionSize, const Vec4& color, const Vec4& colorThreshold)
    698 {
    699 	const Vec4	minColor	= color - colorThreshold;
    700 	const Vec4	maxColor	= color + colorThreshold;
    701 	const int	xEnd		= regionOffset.x() + regionSize.x();
    702 	const int	yEnd		= regionOffset.y() + regionSize.y();
    703 	int			numPixels	= 0;
    704 
    705 	DE_ASSERT(xEnd <= pixels.getWidth());
    706 	DE_ASSERT(yEnd <= pixels.getHeight());
    707 
    708 	for (int y = regionOffset.y(); y < yEnd; ++y)
    709 	for (int x = regionOffset.x(); x < xEnd; ++x)
    710 	{
    711 		if (isColorInRange(pixels.getPixel(x, y), minColor, maxColor))
    712 			++numPixels;
    713 	}
    714 
    715 	return numPixels;
    716 }
    717 
    718 int countPixels (const tcu::ConstPixelBufferAccess pixels, const Vec4& color, const Vec4& colorThreshold)
    719 {
    720 	return countPixels(pixels, IVec2(), IVec2(pixels.getWidth(), pixels.getHeight()), color, colorThreshold);
    721 }
    722 
    723 //! Clipping against the default clip volume.
    724 namespace ClipVolume
    725 {
    726 
    727 //! Used by wide lines test.
    728 enum LineOrientation
    729 {
    730 	LINE_ORIENTATION_AXIS_ALIGNED,
    731 	LINE_ORIENTATION_DIAGONAL,
    732 };
    733 
    734 void addSimplePrograms (SourceCollections& programCollection, const float pointSize = 0.0f)
    735 {
    736 	// Vertex shader
    737 	{
    738 		const bool usePointSize = pointSize > 0.0f;
    739 
    740 		std::ostringstream src;
    741 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    742 			<< "\n"
    743 			<< "layout(location = 0) in vec4 v_position;\n"
    744 			<< "\n"
    745 			<< "out gl_PerVertex {\n"
    746 			<< "    vec4  gl_Position;\n"
    747 			<< (usePointSize ? "    float gl_PointSize;\n" : "")
    748 			<< "};\n"
    749 			<< "\n"
    750 			<< "void main (void)\n"
    751 			<< "{\n"
    752 			<< "    gl_Position = v_position;\n"
    753 			<< (usePointSize ? "    gl_PointSize = " + de::floatToString(pointSize, 1) + ";\n" : "")
    754 			<< "}\n";
    755 
    756 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    757 	}
    758 
    759 	// Fragment shader
    760 	{
    761 		std::ostringstream src;
    762 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
    763 			<< "\n"
    764 			<< "layout(location = 0) out vec4 o_color;\n"
    765 			<< "\n"
    766 			<< "void main (void)\n"
    767 			<< "{\n"
    768 			<< "    o_color = vec4(1.0, gl_FragCoord.z, 0.0, 1.0);\n"
    769 			<< "}\n";
    770 
    771 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    772 	}
    773 }
    774 
    775 void initPrograms (SourceCollections& programCollection, const VkPrimitiveTopology topology)
    776 {
    777 	const float pointSize = (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? 1.0f : 0.0f);
    778 	addSimplePrograms(programCollection, pointSize);
    779 }
    780 
    781 void initPrograms (SourceCollections& programCollection, const LineOrientation lineOrientation)
    782 {
    783 	DE_UNREF(lineOrientation);
    784 	addSimplePrograms(programCollection);
    785 }
    786 
    787 void initProgramsPointSize (SourceCollections& programCollection)
    788 {
    789 	addSimplePrograms(programCollection, 0.75f * RENDER_SIZE);
    790 }
    791 
    792 //! Primitives fully inside the clip volume.
    793 tcu::TestStatus testPrimitivesInside (Context& context, const VkPrimitiveTopology topology)
    794 {
    795 	int minExpectedBlackPixels = 0;
    796 
    797 	switch (topology)
    798 	{
    799 		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
    800 			// We draw only 5 points.
    801 			minExpectedBlackPixels = NUM_RENDER_PIXELS - 5;
    802 			break;
    803 
    804 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
    805 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
    806 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
    807 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
    808 			// Allow for some error.
    809 			minExpectedBlackPixels = NUM_RENDER_PIXELS - 3 * RENDER_SIZE;
    810 			break;
    811 
    812 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
    813 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
    814 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
    815 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
    816 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
    817 			// All render area should be covered.
    818 			minExpectedBlackPixels = 0;
    819 			break;
    820 
    821 		default:
    822 			DE_ASSERT(0);
    823 			break;
    824 	}
    825 
    826 	std::vector<Shader> shaders;
    827 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
    828 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
    829 
    830 	tcu::TestLog&	log			= context.getTestContext().getLog();
    831 	int				numPassed	= 0;
    832 
    833 	static const struct
    834 	{
    835 		const char* const	desc;
    836 		float				zPos;
    837 	} cases[] =
    838 	{
    839 		{ "Draw primitives at near clipping plane, z = 0.0",	0.0f, },
    840 		{ "Draw primitives at z = 0.5",							0.5f, },
    841 		{ "Draw primitives at far clipping plane, z = 1.0",		1.0f, },
    842 	};
    843 
    844 	for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
    845 	{
    846 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
    847 
    848 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
    849 		DrawContext drawContext(context, shaders, vertices, topology);
    850 		drawContext.draw();
    851 
    852 		const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
    853 		if (numBlackPixels >= minExpectedBlackPixels)
    854 			++numPassed;
    855 	}
    856 
    857 	return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
    858 }
    859 
    860 //! Primitives fully outside the clip volume.
    861 tcu::TestStatus testPrimitivesOutside (Context& context, const VkPrimitiveTopology topology)
    862 {
    863 	std::vector<Shader> shaders;
    864 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
    865 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
    866 
    867 	tcu::TestLog&	log			= context.getTestContext().getLog();
    868 	int				numPassed	= 0;
    869 
    870 	static const struct
    871 	{
    872 		const char* const	desc;
    873 		float				zPos;
    874 	} cases[] =
    875 	{
    876 		{ "Draw primitives in front of the near clipping plane, z < 0.0",	-0.5f, },
    877 		{ "Draw primitives behind the far clipping plane, z > 1.0",			 1.5f, },
    878 	};
    879 
    880 	log << tcu::TestLog::Message << "Drawing primitives outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage;
    881 
    882 	for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
    883 	{
    884 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
    885 
    886 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f);
    887 		DrawContext drawContext(context, shaders, vertices, topology);
    888 		drawContext.draw();
    889 
    890 		// All pixels must be black -- nothing is drawn.
    891 		const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
    892 		if (numBlackPixels == NUM_RENDER_PIXELS)
    893 			++numPassed;
    894 	}
    895 
    896 	return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
    897 }
    898 
    899 //! Primitives partially outside the clip volume, but depth clamped
    900 tcu::TestStatus testPrimitivesDepthClamp (Context& context, const VkPrimitiveTopology topology)
    901 {
    902 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_DEPTH_CLAMP);
    903 
    904 	std::vector<Shader> shaders;
    905 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
    906 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
    907 
    908 	const int		numCases		= 4;
    909 	const IVec2		regionSize		= IVec2(RENDER_SIZE/2, RENDER_SIZE);	//! size of the clamped region
    910 	const int		regionPixels	= regionSize.x() * regionSize.y();
    911 	tcu::TestLog&	log				= context.getTestContext().getLog();
    912 	int				numPassed		= 0;
    913 
    914 	static const struct
    915 	{
    916 		const char* const	desc;
    917 		float				zPos;
    918 		bool				depthClampEnable;
    919 		IVec2				regionOffset;
    920 		Vec4				color;
    921 	} cases[numCases] =
    922 	{
    923 		{ "Draw primitives intersecting the near clipping plane, depth clamp disabled",	-0.5f,	false,	IVec2(0, 0),				Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
    924 		{ "Draw primitives intersecting the near clipping plane, depth clamp enabled",	-0.5f,	true,	IVec2(0, 0),				Vec4(1.0f, 0.0f, 0.0f, 1.0f) },
    925 		{ "Draw primitives intersecting the far clipping plane, depth clamp disabled",	 0.5f,	false,	IVec2(RENDER_SIZE/2, 0),	Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
    926 		{ "Draw primitives intersecting the far clipping plane, depth clamp enabled",	 0.5f,	true,	IVec2(RENDER_SIZE/2, 0),	Vec4(1.0f, 1.0f, 0.0f, 1.0f) },
    927 	};
    928 
    929 	// Per case minimum number of colored pixels.
    930 	int caseMinPixels[numCases] = { 0, 0, 0, 0 };
    931 
    932 	switch (topology)
    933 	{
    934 		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
    935 			caseMinPixels[0] = caseMinPixels[2] = regionPixels - 1;
    936 			caseMinPixels[1] = caseMinPixels[3] = 2;
    937 			break;
    938 
    939 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
    940 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
    941 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
    942 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
    943 			caseMinPixels[0] = regionPixels;
    944 			caseMinPixels[1] = RENDER_SIZE - 2;
    945 			caseMinPixels[2] = regionPixels;
    946 			caseMinPixels[3] = 2 * (RENDER_SIZE - 2);
    947 			break;
    948 
    949 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
    950 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
    951 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
    952 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
    953 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
    954 			caseMinPixels[0] = caseMinPixels[1] = caseMinPixels[2] = caseMinPixels[3] = regionPixels;
    955 			break;
    956 
    957 		default:
    958 			DE_ASSERT(0);
    959 			break;
    960 	}
    961 
    962 	for (int caseNdx = 0; caseNdx < numCases; ++caseNdx)
    963 	{
    964 		log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage;
    965 
    966 		const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 1.0f);
    967 		DrawContext drawContext(context, shaders, vertices, topology, static_cast<deUint32>(RENDER_SIZE), cases[caseNdx].depthClampEnable);
    968 		drawContext.draw();
    969 
    970 		const int numPixels = countPixels(drawContext.getColorPixels(), cases[caseNdx].regionOffset, regionSize, cases[caseNdx].color, Vec4());
    971 
    972 		if (numPixels >= caseMinPixels[caseNdx])
    973 			++numPassed;
    974 	}
    975 
    976 	return (numPassed == numCases ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
    977 }
    978 
    979 //! Large point clipping
    980 //! Spec: If the primitive under consideration is a point, then clipping passes it unchanged if it lies within the clip volume;
    981 //!       otherwise, it is discarded.
    982 tcu::TestStatus testLargePoints (Context& context)
    983 {
    984 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_LARGE_POINTS);
    985 
    986 	std::vector<Shader> shaders;
    987 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
    988 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
    989 
    990 	std::vector<Vec4> vertices;
    991 	{
    992 		const float delta	= 0.1f;  // much smaller than the point size
    993 		const float p		= 1.0f + delta;
    994 
    995 		vertices.push_back(Vec4(  -p,   -p, 0.1f, 1.0f));
    996 		vertices.push_back(Vec4(  -p,    p, 0.2f, 1.0f));
    997 		vertices.push_back(Vec4(   p,    p, 0.4f, 1.0f));
    998 		vertices.push_back(Vec4(   p,   -p, 0.6f, 1.0f));
    999 		vertices.push_back(Vec4(0.0f,   -p, 0.8f, 1.0f));
   1000 		vertices.push_back(Vec4(   p, 0.0f, 0.9f, 1.0f));
   1001 		vertices.push_back(Vec4(0.0f,    p, 0.1f, 1.0f));
   1002 		vertices.push_back(Vec4(  -p, 0.0f, 0.2f, 1.0f));
   1003 	}
   1004 
   1005 	tcu::TestLog&	log	= context.getTestContext().getLog();
   1006 
   1007 	log << tcu::TestLog::Message << "Drawing several large points just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage;
   1008 
   1009 	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
   1010 	drawContext.draw();
   1011 
   1012 	// All pixels must be black -- nothing is drawn.
   1013 	const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
   1014 
   1015 	return (numBlackPixels == NUM_RENDER_PIXELS ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
   1016 }
   1017 
   1018 //! Wide line clipping
   1019 //! Spec: If the primitive is a line segment, then clipping does nothing to it if it lies entirely within the clip volume, and discards it
   1020 //!       if it lies entirely outside the volume.
   1021 tcu::TestStatus testWideLines (Context& context, const LineOrientation lineOrientation)
   1022 {
   1023 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_WIDE_LINES);
   1024 
   1025 	std::vector<Shader> shaders;
   1026 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
   1027 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
   1028 
   1029 	const float delta = 0.1f;  // much smaller than the line width
   1030 
   1031 	std::vector<Vec4> vertices;
   1032 	if (lineOrientation == LINE_ORIENTATION_AXIS_ALIGNED)
   1033 	{
   1034 		// Axis-aligned lines just outside the clip volume.
   1035 		const float p = 1.0f + delta;
   1036 		const float q = 0.9f;
   1037 
   1038 		vertices.push_back(Vec4(-p, -q, 0.1f, 1.0f));
   1039 		vertices.push_back(Vec4(-p,  q, 0.9f, 1.0f));	// line 0
   1040 		vertices.push_back(Vec4(-q,  p, 0.1f, 1.0f));
   1041 		vertices.push_back(Vec4( q,  p, 0.9f, 1.0f));	// line 1
   1042 		vertices.push_back(Vec4( p,  q, 0.1f, 1.0f));
   1043 		vertices.push_back(Vec4( p, -q, 0.9f, 1.0f));	// line 2
   1044 		vertices.push_back(Vec4( q, -p, 0.1f, 1.0f));
   1045 		vertices.push_back(Vec4(-q, -p, 0.9f, 1.0f));	// line 3
   1046 	}
   1047 	else if (lineOrientation == LINE_ORIENTATION_DIAGONAL)
   1048 	{
   1049 		// Diagonal lines just outside the clip volume.
   1050 		const float p = 2.0f + delta;
   1051 
   1052 		vertices.push_back(Vec4(  -p, 0.0f, 0.1f, 1.0f));
   1053 		vertices.push_back(Vec4(0.0f,   -p, 0.9f, 1.0f));	// line 0
   1054 		vertices.push_back(Vec4(0.0f,   -p, 0.1f, 1.0f));
   1055 		vertices.push_back(Vec4(   p, 0.0f, 0.9f, 1.0f));	// line 1
   1056 		vertices.push_back(Vec4(   p, 0.0f, 0.1f, 1.0f));
   1057 		vertices.push_back(Vec4(0.0f,    p, 0.9f, 1.0f));	// line 2
   1058 		vertices.push_back(Vec4(0.0f,    p, 0.1f, 1.0f));
   1059 		vertices.push_back(Vec4(  -p, 0.0f, 0.9f, 1.0f));	// line 3
   1060 	}
   1061 	else
   1062 		DE_ASSERT(0);
   1063 
   1064 	const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits;
   1065 
   1066 	const float		lineWidth	= std::min(static_cast<float>(RENDER_SIZE), limits.lineWidthRange[1]);
   1067 	tcu::TestLog&	log			= context.getTestContext().getLog();
   1068 
   1069 	log << tcu::TestLog::Message << "Drawing several wide lines just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage
   1070 		<< tcu::TestLog::Message << "Line width is " << lineWidth << "." << tcu::TestLog::EndMessage;
   1071 
   1072 	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, static_cast<deUint32>(RENDER_SIZE), false, false, lineWidth);
   1073 	drawContext.draw();
   1074 
   1075 	// All pixels must be black -- nothing is drawn.
   1076 	const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
   1077 
   1078 	return (numBlackPixels == NUM_RENDER_PIXELS ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
   1079 }
   1080 
   1081 } // ClipVolume ns
   1082 
   1083 namespace ClipDistance
   1084 {
   1085 
   1086 struct CaseDefinition
   1087 {
   1088 	const VkPrimitiveTopology	topology;
   1089 	const bool					dynamicIndexing;
   1090 	const bool					enableTessellation;
   1091 	const bool					enableGeometry;
   1092 	const int					numClipDistances;
   1093 	const int					numCullDistances;
   1094 
   1095 	CaseDefinition (const VkPrimitiveTopology	topology_,
   1096 					const int					numClipDistances_,
   1097 					const int					numCullDistances_,
   1098 					const bool					enableTessellation_,
   1099 					const bool					enableGeometry_,
   1100 					const bool					dynamicIndexing_)
   1101 		: topology					(topology_)
   1102 		, dynamicIndexing			(dynamicIndexing_)
   1103 		, enableTessellation		(enableTessellation_)
   1104 		, enableGeometry			(enableGeometry_)
   1105 		, numClipDistances			(numClipDistances_)
   1106 		, numCullDistances			(numCullDistances_)
   1107 	{
   1108 	}
   1109 };
   1110 
   1111 void initPrograms (SourceCollections& programCollection, const CaseDefinition caseDef)
   1112 {
   1113 	DE_ASSERT(caseDef.numClipDistances + caseDef.numCullDistances <= MAX_COMBINED_CLIP_AND_CULL_DISTANCES);
   1114 
   1115 	std::string perVertexBlock;
   1116 	{
   1117 		std::ostringstream str;
   1118 		str << "gl_PerVertex {\n"
   1119 			<< "    vec4  gl_Position;\n";
   1120 		if (caseDef.numClipDistances > 0)
   1121 			str << "    float gl_ClipDistance[" << caseDef.numClipDistances << "];\n";
   1122 		if (caseDef.numCullDistances > 0)
   1123 			str << "    float gl_CullDistance[" << caseDef.numCullDistances << "];\n";
   1124 		str << "}";
   1125 		perVertexBlock = str.str();
   1126 	}
   1127 
   1128 	// Vertex shader
   1129 	{
   1130 		std::ostringstream src;
   1131 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1132 			<< "\n"
   1133 			<< "layout(location = 0) in  vec4 v_position;\n"
   1134 			<< "layout(location = 0) out vec4 out_color;\n"
   1135 			<< "\n"
   1136 			<< "out " << perVertexBlock << ";\n"
   1137 			<< "\n"
   1138 			<< "void main (void)\n"
   1139 			<< "{\n"
   1140 			<< "    gl_Position = v_position;\n"
   1141 			<< "    out_color   = vec4(1.0, 0.5 * (v_position.x + 1.0), 0.0, 1.0);\n"
   1142 			<< "\n"
   1143 			<< "    const int barNdx = gl_VertexIndex / 6;\n";
   1144 		if (caseDef.dynamicIndexing)
   1145 		{
   1146 			if (caseDef.numClipDistances > 0)
   1147 				src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
   1148 					<< "        gl_ClipDistance[i] = (barNdx == i ? v_position.y : 0.0);\n";
   1149 			if (caseDef.numCullDistances > 0)
   1150 				src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
   1151 					<< "        gl_CullDistance[i] = 0.0;\n";
   1152 		}
   1153 		else
   1154 		{
   1155 			for (int i = 0; i < caseDef.numClipDistances; ++i)
   1156 				src << "    gl_ClipDistance[" << i << "] = (barNdx == " << i << " ? v_position.y : 0.0);\n";
   1157 			for (int i = 0; i < caseDef.numCullDistances; ++i)
   1158 				src << "    gl_CullDistance[" << i << "] = 0.0;\n";		// don't cull anything
   1159 		}
   1160 		src	<< "}\n";
   1161 
   1162 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
   1163 	}
   1164 
   1165 	if (caseDef.enableTessellation)
   1166 	{
   1167 		std::ostringstream src;
   1168 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1169 			<< "\n"
   1170 			<< "layout(vertices = " << NUM_PATCH_CONTROL_POINTS << ") out;\n"
   1171 			<< "\n"
   1172 			<< "layout(location = 0) in  vec4 in_color[];\n"
   1173 			<< "layout(location = 0) out vec4 out_color[];\n"
   1174 			<< "\n"
   1175 			<< "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
   1176 			<< "\n"
   1177 			<< "out " << perVertexBlock << " gl_out[];\n"
   1178 			<< "\n"
   1179 			<< "void main (void)\n"
   1180 			<< "{\n"
   1181 			<< "    gl_TessLevelInner[0] = 1.0;\n"
   1182 			<< "    gl_TessLevelInner[1] = 1.0;\n"
   1183 			<< "\n"
   1184 			<< "    gl_TessLevelOuter[0] = 1.0;\n"
   1185 			<< "    gl_TessLevelOuter[1] = 1.0;\n"
   1186 			<< "    gl_TessLevelOuter[2] = 1.0;\n"
   1187 			<< "    gl_TessLevelOuter[3] = 1.0;\n"
   1188 			<< "\n"
   1189 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
   1190 			<< "    out_color[gl_InvocationID]          = in_color[gl_InvocationID];\n"
   1191 			<< "\n";
   1192 		if (caseDef.dynamicIndexing)
   1193 		{
   1194 			if (caseDef.numClipDistances > 0)
   1195 				src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
   1196 					<< "        gl_out[gl_InvocationID].gl_ClipDistance[i] = gl_in[gl_InvocationID].gl_ClipDistance[i];\n";
   1197 			if (caseDef.numCullDistances > 0)
   1198 				src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
   1199 					<< "        gl_out[gl_InvocationID].gl_CullDistance[i] = gl_in[gl_InvocationID].gl_CullDistance[i];\n";
   1200 		}
   1201 		else
   1202 		{
   1203 			for (int i = 0; i < caseDef.numClipDistances; ++i)
   1204 				src << "    gl_out[gl_InvocationID].gl_ClipDistance[" << i << "] = gl_in[gl_InvocationID].gl_ClipDistance[" << i << "];\n";
   1205 			for (int i = 0; i < caseDef.numCullDistances; ++i)
   1206 				src << "    gl_out[gl_InvocationID].gl_CullDistance[" << i << "] = gl_in[gl_InvocationID].gl_CullDistance[" << i << "];\n";
   1207 		}
   1208 		src << "}\n";
   1209 
   1210 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
   1211 	}
   1212 
   1213 	if (caseDef.enableTessellation)
   1214 	{
   1215 		DE_ASSERT(NUM_PATCH_CONTROL_POINTS == 3);  // assumed in shader code
   1216 
   1217 		std::ostringstream src;
   1218 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1219 			<< "\n"
   1220 			<< "layout(triangles, equal_spacing, ccw) in;\n"
   1221 			<< "\n"
   1222 			<< "layout(location = 0) in  vec4 in_color[];\n"
   1223 			<< "layout(location = 0) out vec4 out_color;\n"
   1224 			<< "\n"
   1225 			<< "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
   1226 			<< "\n"
   1227 			<< "out " << perVertexBlock << ";\n"
   1228 			<< "\n"
   1229 			<< "void main (void)\n"
   1230 			<< "{\n"
   1231 			<< "    vec3 px     = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
   1232 			<< "    vec3 py     = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
   1233 			<< "    vec3 pz     = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
   1234 			<< "    gl_Position = vec4(px + py + pz, 1.0);\n"
   1235 			<< "    out_color   = (in_color[0] + in_color[1] + in_color[2]) / 3.0;\n"
   1236 			<< "\n";
   1237 		if (caseDef.dynamicIndexing)
   1238 		{
   1239 			if (caseDef.numClipDistances > 0)
   1240 				src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
   1241 					<< "        gl_ClipDistance[i] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[i]\n"
   1242 					<< "                           + gl_TessCoord.y * gl_in[1].gl_ClipDistance[i]\n"
   1243 					<< "                           + gl_TessCoord.z * gl_in[2].gl_ClipDistance[i];\n";
   1244 			if (caseDef.numCullDistances > 0)
   1245 				src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
   1246 					<< "        gl_CullDistance[i] = gl_TessCoord.x * gl_in[0].gl_CullDistance[i]\n"
   1247 					<< "                           + gl_TessCoord.y * gl_in[1].gl_CullDistance[i]\n"
   1248 					<< "                           + gl_TessCoord.z * gl_in[2].gl_CullDistance[i];\n";
   1249 		}
   1250 		else
   1251 		{
   1252 			for (int i = 0; i < caseDef.numClipDistances; ++i)
   1253 				src << "    gl_ClipDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[" << i << "]\n"
   1254 					<< "                       + gl_TessCoord.y * gl_in[1].gl_ClipDistance[" << i << "]\n"
   1255 					<< "                       + gl_TessCoord.z * gl_in[2].gl_ClipDistance[" << i << "];\n";
   1256 			for (int i = 0; i < caseDef.numCullDistances; ++i)
   1257 				src << "    gl_CullDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_CullDistance[" << i << "]\n"
   1258 					<< "                       + gl_TessCoord.y * gl_in[1].gl_CullDistance[" << i << "]\n"
   1259 					<< "                       + gl_TessCoord.z * gl_in[2].gl_CullDistance[" << i << "];\n";
   1260 		}
   1261 		src << "}\n";
   1262 
   1263 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
   1264 	}
   1265 
   1266 	if (caseDef.enableGeometry)
   1267 	{
   1268 		std::ostringstream src;
   1269 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1270 			<< "\n"
   1271 			<< "layout(triangles) in;\n"
   1272 			<< "layout(triangle_strip, max_vertices = 3) out;\n"
   1273 			<< "\n"
   1274 			<< "layout(location = 0) in  vec4 in_color[];\n"
   1275 			<< "layout(location = 0) out vec4 out_color;\n"
   1276 			<< "\n"
   1277 			<< "in " << perVertexBlock << " gl_in[];\n"
   1278 			<< "\n"
   1279 			<< "out " << perVertexBlock << ";\n"
   1280 			<< "\n"
   1281 			<< "void main (void)\n"
   1282 			<< "{\n";
   1283 		for (int vertNdx = 0; vertNdx < 3; ++vertNdx)
   1284 		{
   1285 			if (vertNdx > 0)
   1286 				src << "\n";
   1287 			src << "    gl_Position = gl_in[" << vertNdx << "].gl_Position;\n"
   1288 				<< "    out_color   = in_color[" << vertNdx << "];\n";
   1289 			if (caseDef.dynamicIndexing)
   1290 			{
   1291 				if (caseDef.numClipDistances > 0)
   1292 					src << "    for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n"
   1293 						<< "        gl_ClipDistance[i] = gl_in[" << vertNdx << "].gl_ClipDistance[i];\n";
   1294 				if (caseDef.numCullDistances > 0)
   1295 					src << "    for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n"
   1296 						<< "        gl_CullDistance[i] = gl_in[" << vertNdx << "].gl_CullDistance[i];\n";
   1297 			}
   1298 			else
   1299 			{
   1300 				for (int i = 0; i < caseDef.numClipDistances; ++i)
   1301 					src << "    gl_ClipDistance[" << i << "] = gl_in[" << vertNdx << "].gl_ClipDistance[" << i << "];\n";
   1302 				for (int i = 0; i < caseDef.numCullDistances; ++i)
   1303 					src << "    gl_CullDistance[" << i << "] = gl_in[" << vertNdx << "].gl_CullDistance[" << i << "];\n";
   1304 			}
   1305 			src << "    EmitVertex();\n";
   1306 		}
   1307 		src	<< "}\n";
   1308 
   1309 		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
   1310 	}
   1311 
   1312 	// Fragment shader
   1313 	{
   1314 		std::ostringstream src;
   1315 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1316 			<< "\n"
   1317 			<< "layout(location = 0) in flat vec4 in_color;\n"
   1318 			<< "layout(location = 0) out vec4 o_color;\n"
   1319 			<< "\n"
   1320 			<< "void main (void)\n"
   1321 			<< "{\n"
   1322 			<< "    o_color = vec4(in_color.rgb + vec3(0.0, 0.0, 0.5), 1.0);\n"  // mix with a constant color in case variable wasn't passed correctly through stages
   1323 			<< "}\n";
   1324 
   1325 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
   1326 	}
   1327 }
   1328 
   1329 tcu::TestStatus testClipDistance (Context& context, const CaseDefinition caseDef)
   1330 {
   1331 	// Check test requirements
   1332 	{
   1333 		const InstanceInterface&		vki			= context.getInstanceInterface();
   1334 		const VkPhysicalDevice			physDevice	= context.getPhysicalDevice();
   1335 		const VkPhysicalDeviceLimits	limits		= getPhysicalDeviceProperties(vki, physDevice).limits;
   1336 
   1337 		FeatureFlags requirements = (FeatureFlags)0;
   1338 
   1339 		if (caseDef.numClipDistances > 0)
   1340 			requirements |= FEATURE_SHADER_CLIP_DISTANCE;
   1341 		if (caseDef.numCullDistances > 0)
   1342 			requirements |= FEATURE_SHADER_CULL_DISTANCE;
   1343 		if (caseDef.enableTessellation)
   1344 			requirements |= FEATURE_TESSELLATION_SHADER;
   1345 		if (caseDef.enableGeometry)
   1346 			requirements |= FEATURE_GEOMETRY_SHADER;
   1347 
   1348 		requireFeatures(vki, physDevice, requirements);
   1349 
   1350 		// Check limits for supported features
   1351 
   1352 		if (caseDef.numClipDistances > 0 && limits.maxClipDistances < MAX_CLIP_DISTANCES)
   1353 			return tcu::TestStatus::fail("maxClipDistances smaller than the minimum required by the spec");
   1354 		if (caseDef.numCullDistances > 0 && limits.maxCullDistances < MAX_CULL_DISTANCES)
   1355 			return tcu::TestStatus::fail("maxCullDistances smaller than the minimum required by the spec");
   1356 		if (caseDef.numCullDistances > 0 && limits.maxCombinedClipAndCullDistances < MAX_COMBINED_CLIP_AND_CULL_DISTANCES)
   1357 			return tcu::TestStatus::fail("maxCombinedClipAndCullDistances smaller than the minimum required by the spec");
   1358 	}
   1359 
   1360 	std::vector<Shader> shaders;
   1361 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
   1362 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
   1363 	if (caseDef.enableTessellation)
   1364 	{
   1365 		shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,		context.getBinaryCollection().get("tesc")));
   1366 		shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,	context.getBinaryCollection().get("tese")));
   1367 	}
   1368 	if (caseDef.enableGeometry)
   1369 		shaders.push_back(Shader(VK_SHADER_STAGE_GEOMETRY_BIT,	context.getBinaryCollection().get("geom")));
   1370 
   1371 	const int numBars = MAX_COMBINED_CLIP_AND_CULL_DISTANCES;
   1372 
   1373 	std::vector<Vec4> vertices;
   1374 	{
   1375 		const float	dx = 2.0f / numBars;
   1376 		for (int i = 0; i < numBars; ++i)
   1377 		{
   1378 			const float x = -1.0f + dx * static_cast<float>(i);
   1379 
   1380 			vertices.push_back(Vec4(x,      -1.0f, 0.0f, 1.0f));
   1381 			vertices.push_back(Vec4(x,       1.0f, 0.0f, 1.0f));
   1382 			vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f));
   1383 
   1384 			vertices.push_back(Vec4(x,       1.0f, 0.0f, 1.0f));
   1385 			vertices.push_back(Vec4(x + dx,  1.0f, 0.0f, 1.0f));
   1386 			vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f));
   1387 		}
   1388 	}
   1389 
   1390 	tcu::TestLog& log = context.getTestContext().getLog();
   1391 
   1392 	log << tcu::TestLog::Message << "Drawing " << numBars << " colored bars, clipping the first " << caseDef.numClipDistances << tcu::TestLog::EndMessage
   1393 		<< tcu::TestLog::Message << "Using " << caseDef.numClipDistances << " ClipDistance(s) and " << caseDef.numCullDistances << " CullDistance(s)" << tcu::TestLog::EndMessage
   1394 		<< tcu::TestLog::Message << "Expecting upper half of the clipped bars to be black." << tcu::TestLog::EndMessage;
   1395 
   1396 	DrawContext drawContext(context, shaders, vertices, caseDef.topology);
   1397 	drawContext.draw();
   1398 
   1399 	// Count black pixels in the whole image.
   1400 	const int numBlackPixels		= countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
   1401 	const IVec2	clipRegion			= IVec2(caseDef.numClipDistances * RENDER_SIZE / numBars, RENDER_SIZE / 2);
   1402 	const int expectedClippedPixels	= clipRegion.x() * clipRegion.y();
   1403 	// Make sure the bottom half has no black pixels (possible if image became corrupted).
   1404 	const int guardPixels			= countPixels(drawContext.getColorPixels(), IVec2(0, RENDER_SIZE/2), clipRegion, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4());
   1405 
   1406 	return (numBlackPixels == expectedClippedPixels && guardPixels == 0 ? tcu::TestStatus::pass("OK")
   1407 																		: tcu::TestStatus::fail("Rendered image(s) are incorrect"));
   1408 }
   1409 
   1410 } // ClipDistance ns
   1411 
   1412 namespace ClipDistanceComplementarity
   1413 {
   1414 
   1415 void initPrograms (SourceCollections& programCollection, const int numClipDistances)
   1416 {
   1417 	// Vertex shader
   1418 	{
   1419 		DE_ASSERT(numClipDistances > 0);
   1420 		const int clipDistanceLastNdx = numClipDistances - 1;
   1421 
   1422 		std::ostringstream src;
   1423 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1424 			<< "\n"
   1425 			<< "layout(location = 0) in vec4 v_position;    // we are passing ClipDistance in w component\n"
   1426 			<< "\n"
   1427 			<< "out gl_PerVertex {\n"
   1428 			<< "    vec4  gl_Position;\n"
   1429 			<< "    float gl_ClipDistance[" << numClipDistances << "];\n"
   1430 			<< "};\n"
   1431 			<< "\n"
   1432 			<< "void main (void)\n"
   1433 			<< "{\n"
   1434 			<< "    gl_Position        = vec4(v_position.xyz, 1.0);\n";
   1435 		for (int i = 0; i < clipDistanceLastNdx; ++i)
   1436 			src << "    gl_ClipDistance[" << i << "] = 0.0;\n";
   1437 		src << "    gl_ClipDistance[" << clipDistanceLastNdx << "] = v_position.w;\n"
   1438 			<< "}\n";
   1439 
   1440 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
   1441 	}
   1442 
   1443 	// Fragment shader
   1444 	{
   1445 		std::ostringstream src;
   1446 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
   1447 			<< "\n"
   1448 			<< "layout(location = 0) out vec4 o_color;\n"
   1449 			<< "\n"
   1450 			<< "void main (void)\n"
   1451 			<< "{\n"
   1452 			<< "    o_color = vec4(1.0, 1.0, 1.0, 0.5);\n"
   1453 			<< "}\n";
   1454 
   1455 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
   1456 	}
   1457 }
   1458 
   1459 tcu::TestStatus testComplementarity (Context& context, const int numClipDistances)
   1460 {
   1461 	// Check test requirements
   1462 	{
   1463 		const InstanceInterface&		vki			= context.getInstanceInterface();
   1464 		const VkPhysicalDevice			physDevice	= context.getPhysicalDevice();
   1465 
   1466 		requireFeatures(vki, physDevice, FEATURE_SHADER_CLIP_DISTANCE);
   1467 	}
   1468 
   1469 	std::vector<Shader> shaders;
   1470 	shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT,	context.getBinaryCollection().get("vert")));
   1471 	shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT,	context.getBinaryCollection().get("frag")));
   1472 
   1473 	std::vector<Vec4> vertices;
   1474 	{
   1475 		de::Random	rnd						(1234);
   1476 		const int	numSections				= 16;
   1477 		const int	numVerticesPerSection	= 4;	// logical verticies, due to triangle list topology we actually use 6 per section
   1478 
   1479 		DE_ASSERT(RENDER_SIZE_LARGE % numSections == 0);
   1480 
   1481 		std::vector<float> clipDistances(numVerticesPerSection * numSections);
   1482 		for (int i = 0; i < static_cast<int>(clipDistances.size()); ++i)
   1483 			clipDistances[i] = rnd.getFloat(-1.0f, 1.0f);
   1484 
   1485 		// Two sets of identical primitives, but with a different ClipDistance sign.
   1486 		for (int setNdx = 0; setNdx < 2; ++setNdx)
   1487 		{
   1488 			const float sign = (setNdx == 0 ? 1.0f : -1.0f);
   1489 			const float	dx	 = 2.0f / static_cast<float>(numSections);
   1490 
   1491 			for (int i = 0; i < numSections; ++i)
   1492 			{
   1493 				const int	ndxBase	= numVerticesPerSection * i;
   1494 				const float x		= -1.0f + dx * static_cast<float>(i);
   1495 				const Vec4	p0		= Vec4(x,      -1.0f, 0.0f, sign * clipDistances[ndxBase + 0]);
   1496 				const Vec4	p1		= Vec4(x,       1.0f, 0.0f, sign * clipDistances[ndxBase + 1]);
   1497 				const Vec4	p2		= Vec4(x + dx,  1.0f, 0.0f, sign * clipDistances[ndxBase + 2]);
   1498 				const Vec4	p3		= Vec4(x + dx, -1.0f, 0.0f, sign * clipDistances[ndxBase + 3]);
   1499 
   1500 				vertices.push_back(p0);
   1501 				vertices.push_back(p1);
   1502 				vertices.push_back(p2);
   1503 
   1504 				vertices.push_back(p2);
   1505 				vertices.push_back(p3);
   1506 				vertices.push_back(p0);
   1507 			}
   1508 		}
   1509 	}
   1510 
   1511 	tcu::TestLog& log = context.getTestContext().getLog();
   1512 
   1513 	log << tcu::TestLog::Message << "Draw two sets of primitives with blending, differing only with ClipDistance sign." << tcu::TestLog::EndMessage
   1514 		<< tcu::TestLog::Message << "Using " << numClipDistances << " clipping plane(s), one of them possibly having negative values." << tcu::TestLog::EndMessage
   1515 		<< tcu::TestLog::Message << "Expecting a uniform gray area, no missing (black) nor overlapped (white) pixels." << tcu::TestLog::EndMessage;
   1516 
   1517 	DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, static_cast<deUint32>(RENDER_SIZE_LARGE), false, true);
   1518 	drawContext.draw();
   1519 
   1520 	const int numGrayPixels		= countPixels(drawContext.getColorPixels(), Vec4(0.5f, 0.5f, 0.5f, 1.0f), Vec4(0.02f, 0.02f, 0.02f, 0.0f));
   1521 	const int numExpectedPixels	= RENDER_SIZE_LARGE * RENDER_SIZE_LARGE;
   1522 
   1523 	return (numGrayPixels == numExpectedPixels ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect"));
   1524 }
   1525 
   1526 } // ClipDistanceComplementarity ns
   1527 
   1528 void addClippingTests (tcu::TestCaseGroup* clippingTestsGroup)
   1529 {
   1530 	tcu::TestContext& testCtx = clippingTestsGroup->getTestContext();
   1531 
   1532 	// Clipping against the clip volume
   1533 	{
   1534 		using namespace ClipVolume;
   1535 
   1536 		static const VkPrimitiveTopology cases[] =
   1537 		{
   1538 			VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
   1539 			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
   1540 			VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
   1541 			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
   1542 			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
   1543 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
   1544 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
   1545 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
   1546 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
   1547 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
   1548 		};
   1549 
   1550 		MovePtr<tcu::TestCaseGroup> clipVolumeGroup(new tcu::TestCaseGroup(testCtx, "clip_volume", "clipping with the clip volume"));
   1551 
   1552 		// Fully inside the clip volume
   1553 		{
   1554 			MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "inside", ""));
   1555 
   1556 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
   1557 				addFunctionCaseWithPrograms<VkPrimitiveTopology>(
   1558 					group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesInside, cases[caseNdx]);
   1559 
   1560 			clipVolumeGroup->addChild(group.release());
   1561 		}
   1562 
   1563 		// Fully outside the clip volume
   1564 		{
   1565 			MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "outside", ""));
   1566 
   1567 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
   1568 				addFunctionCaseWithPrograms<VkPrimitiveTopology>(
   1569 					group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesOutside, cases[caseNdx]);
   1570 
   1571 			clipVolumeGroup->addChild(group.release());
   1572 		}
   1573 
   1574 		// Depth clamping
   1575 		{
   1576 			MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "depth_clamp", ""));
   1577 
   1578 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
   1579 				addFunctionCaseWithPrograms<VkPrimitiveTopology>(
   1580 					group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesDepthClamp, cases[caseNdx]);
   1581 
   1582 			clipVolumeGroup->addChild(group.release());
   1583 		}
   1584 
   1585 		// Large points and wide lines
   1586 		{
   1587 			// \note For both points and lines, if an unsupported size/width is selected, the nearest supported size will be chosen.
   1588 			//       We do have to check for feature support though.
   1589 
   1590 			MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "clipped", ""));
   1591 
   1592 			addFunctionCaseWithPrograms(group.get(), "large_points", "", initProgramsPointSize, testLargePoints);
   1593 
   1594 			addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_axis_aligned", "", initPrograms, testWideLines, LINE_ORIENTATION_AXIS_ALIGNED);
   1595 			addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_diagonal",	 "", initPrograms, testWideLines, LINE_ORIENTATION_DIAGONAL);
   1596 
   1597 			clipVolumeGroup->addChild(group.release());
   1598 		}
   1599 
   1600 		clippingTestsGroup->addChild(clipVolumeGroup.release());
   1601 	}
   1602 
   1603 	// User-defined clip planes
   1604 	{
   1605 		MovePtr<tcu::TestCaseGroup> clipDistanceGroup(new tcu::TestCaseGroup(testCtx, "user_defined", "user-defined clip planes"));
   1606 
   1607 		// ClipDistance, CullDistance and maxCombinedClipAndCullDistances usage
   1608 		{
   1609 			using namespace ClipDistance;
   1610 
   1611 			static const struct
   1612 			{
   1613 				const char* const	groupName;
   1614 				const char* const	description;
   1615 				bool				useCullDistance;
   1616 			} caseGroups[] =
   1617 			{
   1618 				{ "clip_distance",		"use ClipDistance",										false },
   1619 				{ "clip_cull_distance",	"use ClipDistance and CullDistance at the same time",	true  },
   1620 			};
   1621 
   1622 			const deUint32 flagTessellation = 1u << 0;
   1623 			const deUint32 flagGeometry		= 1u << 1;
   1624 
   1625 			for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(caseGroups); ++groupNdx)
   1626 			for (int indexingMode = 0; indexingMode < 2; ++indexingMode)
   1627 			{
   1628 				const bool			dynamicIndexing	= (indexingMode == 1);
   1629 				const std::string	mainGroupName	= de::toString(caseGroups[groupNdx].groupName) + (dynamicIndexing ? "_dynamic_index" : "");
   1630 
   1631 				MovePtr<tcu::TestCaseGroup>	mainGroup(new tcu::TestCaseGroup(testCtx, mainGroupName.c_str(), ""));
   1632 
   1633 				for (deUint32 shaderMask = 0u; shaderMask <= (flagTessellation | flagGeometry); ++shaderMask)
   1634 				{
   1635 					const bool			useTessellation	= (shaderMask & flagTessellation) != 0;
   1636 					const bool			useGeometry		= (shaderMask & flagGeometry) != 0;
   1637 					const std::string	shaderGroupName	= std::string("vert") + (useTessellation ? "_tess" : "") + (useGeometry ? "_geom" : "");
   1638 
   1639 					MovePtr<tcu::TestCaseGroup>	shaderGroup(new tcu::TestCaseGroup(testCtx, shaderGroupName.c_str(), ""));
   1640 
   1641 					for (int numClipPlanes = 1; numClipPlanes <= MAX_CLIP_DISTANCES; ++numClipPlanes)
   1642 					{
   1643 						const int					numCullPlanes	= (caseGroups[groupNdx].useCullDistance
   1644 																		? std::min(static_cast<int>(MAX_CULL_DISTANCES), MAX_COMBINED_CLIP_AND_CULL_DISTANCES - numClipPlanes)
   1645 																		: 0);
   1646 						const std::string			caseName		= de::toString(numClipPlanes) + (numCullPlanes > 0 ? "_" + de::toString(numCullPlanes) : "");
   1647 						const VkPrimitiveTopology	topology		= (useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
   1648 
   1649 						addFunctionCaseWithPrograms<CaseDefinition>(
   1650 							shaderGroup.get(), caseName, caseGroups[groupNdx].description, initPrograms, testClipDistance,
   1651 							CaseDefinition(topology, numClipPlanes, numCullPlanes, useTessellation, useGeometry, dynamicIndexing));
   1652 					}
   1653 					mainGroup->addChild(shaderGroup.release());
   1654 				}
   1655 				clipDistanceGroup->addChild(mainGroup.release());
   1656 			}
   1657 		}
   1658 
   1659 		// Complementarity criterion (i.e. clipped and not clipped areas must add up to a complete primitive with no holes nor overlap)
   1660 		{
   1661 			using namespace ClipDistanceComplementarity;
   1662 
   1663 			MovePtr<tcu::TestCaseGroup>	group(new tcu::TestCaseGroup(testCtx, "complementarity", ""));
   1664 
   1665 			for (int numClipDistances = 1; numClipDistances <= MAX_CLIP_DISTANCES; ++numClipDistances)
   1666 				addFunctionCaseWithPrograms<int>(group.get(), de::toString(numClipDistances).c_str(), "", initPrograms, testComplementarity, numClipDistances);
   1667 
   1668 			clippingTestsGroup->addChild(group.release());
   1669 		}
   1670 
   1671 		clippingTestsGroup->addChild(clipDistanceGroup.release());
   1672 	}
   1673 }
   1674 
   1675 } // anonymous
   1676 
   1677 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
   1678 {
   1679 	return createTestGroup(testCtx, "clipping", "Clipping tests", addClippingTests);
   1680 }
   1681 
   1682 } // clipping
   1683 } // vkt
   1684