Home | History | Annotate | Download | only in tessellation
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2014 The Android Open Source Project
      6  * Copyright (c) 2016 The Khronos Group Inc.
      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 Tessellation Utilities
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktTessellationUtil.hpp"
     26 #include "vkTypeUtil.hpp"
     27 #include "deMath.h"
     28 
     29 namespace vkt
     30 {
     31 namespace tessellation
     32 {
     33 
     34 using namespace vk;
     35 
     36 VkBufferCreateInfo makeBufferCreateInfo (const VkDeviceSize			bufferSize,
     37 										 const VkBufferUsageFlags	usage)
     38 {
     39 	const VkBufferCreateInfo bufferCreateInfo =
     40 	{
     41 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
     42 		DE_NULL,								// const void*			pNext;
     43 		(VkBufferCreateFlags)0,					// VkBufferCreateFlags	flags;
     44 		bufferSize,								// VkDeviceSize			size;
     45 		usage,									// VkBufferUsageFlags	usage;
     46 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
     47 		0u,										// deUint32				queueFamilyIndexCount;
     48 		DE_NULL,								// const deUint32*		pQueueFamilyIndices;
     49 	};
     50 	return bufferCreateInfo;
     51 }
     52 
     53 VkBufferMemoryBarrier makeBufferMemoryBarrier (const VkAccessFlags	srcAccessMask,
     54 											   const VkAccessFlags	dstAccessMask,
     55 											   const VkBuffer		buffer,
     56 											   const VkDeviceSize	offset,
     57 											   const VkDeviceSize	bufferSizeBytes)
     58 {
     59 	const VkBufferMemoryBarrier barrier =
     60 	{
     61 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
     62 		DE_NULL,									// const void*		pNext;
     63 		srcAccessMask,								// VkAccessFlags	srcAccessMask;
     64 		dstAccessMask,								// VkAccessFlags	dstAccessMask;
     65 		VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
     66 		VK_QUEUE_FAMILY_IGNORED,					// deUint32			destQueueFamilyIndex;
     67 		buffer,										// VkBuffer			buffer;
     68 		offset,										// VkDeviceSize		offset;
     69 		bufferSizeBytes,							// VkDeviceSize		size;
     70 	};
     71 	return barrier;
     72 }
     73 
     74 VkImageMemoryBarrier makeImageMemoryBarrier	(const VkAccessFlags			srcAccessMask,
     75 											 const VkAccessFlags			dstAccessMask,
     76 											 const VkImageLayout			oldLayout,
     77 											 const VkImageLayout			newLayout,
     78 											 const VkImage					image,
     79 											 const VkImageSubresourceRange	subresourceRange)
     80 {
     81 	const VkImageMemoryBarrier barrier =
     82 	{
     83 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
     84 		DE_NULL,										// const void*				pNext;
     85 		srcAccessMask,									// VkAccessFlags			outputMask;
     86 		dstAccessMask,									// VkAccessFlags			inputMask;
     87 		oldLayout,										// VkImageLayout			oldLayout;
     88 		newLayout,										// VkImageLayout			newLayout;
     89 		VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
     90 		VK_QUEUE_FAMILY_IGNORED,						// deUint32					destQueueFamilyIndex;
     91 		image,											// VkImage					image;
     92 		subresourceRange,								// VkImageSubresourceRange	subresourceRange;
     93 	};
     94 	return barrier;
     95 }
     96 
     97 Move<VkCommandPool> makeCommandPool (const DeviceInterface& vk, const VkDevice device, const deUint32 queueFamilyIndex)
     98 {
     99 	const VkCommandPoolCreateInfo info =
    100 	{
    101 		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,			// VkStructureType			sType;
    102 		DE_NULL,											// const void*				pNext;
    103 		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,	// VkCommandPoolCreateFlags	flags;
    104 		queueFamilyIndex,									// deUint32					queueFamilyIndex;
    105 	};
    106 	return createCommandPool(vk, device, &info);
    107 }
    108 
    109 
    110 Move<VkDescriptorSet> makeDescriptorSet (const DeviceInterface&			vk,
    111 										 const VkDevice					device,
    112 										 const VkDescriptorPool			descriptorPool,
    113 										 const VkDescriptorSetLayout	setLayout)
    114 {
    115 	const VkDescriptorSetAllocateInfo info =
    116 	{
    117 		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
    118 		DE_NULL,											// const void*					pNext;
    119 		descriptorPool,										// VkDescriptorPool				descriptorPool;
    120 		1u,													// deUint32						descriptorSetCount;
    121 		&setLayout,											// const VkDescriptorSetLayout*	pSetLayouts;
    122 	};
    123 	return allocateDescriptorSet(vk, device, &info);
    124 }
    125 
    126 Move<VkPipelineLayout> makePipelineLayout (const DeviceInterface&		vk,
    127 										   const VkDevice				device,
    128 										   const VkDescriptorSetLayout	descriptorSetLayout)
    129 {
    130 	const VkPipelineLayoutCreateInfo info =
    131 	{
    132 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
    133 		DE_NULL,											// const void*					pNext;
    134 		(VkPipelineLayoutCreateFlags)0,						// VkPipelineLayoutCreateFlags	flags;
    135 		1u,													// deUint32						setLayoutCount;
    136 		&descriptorSetLayout,								// const VkDescriptorSetLayout*	pSetLayouts;
    137 		0u,													// deUint32						pushConstantRangeCount;
    138 		DE_NULL,											// const VkPushConstantRange*	pPushConstantRanges;
    139 	};
    140 	return createPipelineLayout(vk, device, &info);
    141 }
    142 
    143 Move<VkPipelineLayout> makePipelineLayoutWithoutDescriptors (const DeviceInterface&		vk,
    144 															 const VkDevice				device)
    145 {
    146 	const VkPipelineLayoutCreateInfo info =
    147 	{
    148 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
    149 		DE_NULL,											// const void*					pNext;
    150 		(VkPipelineLayoutCreateFlags)0,						// VkPipelineLayoutCreateFlags	flags;
    151 		0u,													// deUint32						setLayoutCount;
    152 		DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
    153 		0u,													// deUint32						pushConstantRangeCount;
    154 		DE_NULL,											// const VkPushConstantRange*	pPushConstantRanges;
    155 	};
    156 	return createPipelineLayout(vk, device, &info);
    157 }
    158 
    159 Move<VkPipeline> makeComputePipeline (const DeviceInterface&		vk,
    160 									  const VkDevice				device,
    161 									  const VkPipelineLayout		pipelineLayout,
    162 									  const VkShaderModule			shaderModule,
    163 									  const VkSpecializationInfo*	specInfo)
    164 {
    165 	const VkPipelineShaderStageCreateInfo shaderStageInfo =
    166 	{
    167 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType					sType;
    168 		DE_NULL,												// const void*						pNext;
    169 		(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags	flags;
    170 		VK_SHADER_STAGE_COMPUTE_BIT,							// VkShaderStageFlagBits			stage;
    171 		shaderModule,											// VkShaderModule					module;
    172 		"main",													// const char*						pName;
    173 		specInfo,												// const VkSpecializationInfo*		pSpecializationInfo;
    174 	};
    175 	const VkComputePipelineCreateInfo pipelineInfo =
    176 	{
    177 		VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,		// VkStructureType					sType;
    178 		DE_NULL,											// const void*						pNext;
    179 		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags			flags;
    180 		shaderStageInfo,									// VkPipelineShaderStageCreateInfo	stage;
    181 		pipelineLayout,										// VkPipelineLayout					layout;
    182 		DE_NULL,											// VkPipeline						basePipelineHandle;
    183 		0,													// deInt32							basePipelineIndex;
    184 	};
    185 	return createComputePipeline(vk, device, DE_NULL , &pipelineInfo);
    186 }
    187 
    188 VkImageCreateInfo makeImageCreateInfo (const tcu::IVec2& size, const VkFormat format, const VkImageUsageFlags usage, const deUint32 numArrayLayers)
    189 {
    190 	const VkImageCreateInfo imageInfo =
    191 	{
    192 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType          sType;
    193 		DE_NULL,									// const void*              pNext;
    194 		(VkImageCreateFlags)0,						// VkImageCreateFlags       flags;
    195 		VK_IMAGE_TYPE_2D,							// VkImageType              imageType;
    196 		format,										// VkFormat                 format;
    197 		makeExtent3D(size.x(), size.y(), 1),		// VkExtent3D               extent;
    198 		1u,											// uint32_t                 mipLevels;
    199 		numArrayLayers,								// uint32_t                 arrayLayers;
    200 		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits    samples;
    201 		VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling            tiling;
    202 		usage,										// VkImageUsageFlags        usage;
    203 		VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode            sharingMode;
    204 		0u,											// uint32_t                 queueFamilyIndexCount;
    205 		DE_NULL,									// const uint32_t*          pQueueFamilyIndices;
    206 		VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout            initialLayout;
    207 	};
    208 	return imageInfo;
    209 }
    210 
    211 Move<VkImageView> makeImageView (const DeviceInterface&			vk,
    212 								 const VkDevice					vkDevice,
    213 								 const VkImage					image,
    214 								 const VkImageViewType			viewType,
    215 								 const VkFormat					format,
    216 								 const VkImageSubresourceRange	subresourceRange)
    217 {
    218 	const VkImageViewCreateInfo imageViewParams =
    219 	{
    220 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// VkStructureType			sType;
    221 		DE_NULL,										// const void*				pNext;
    222 		(VkImageViewCreateFlags)0,						// VkImageViewCreateFlags	flags;
    223 		image,											// VkImage					image;
    224 		viewType,										// VkImageViewType			viewType;
    225 		format,											// VkFormat					format;
    226 		makeComponentMappingRGBA(),						// VkComponentMapping		components;
    227 		subresourceRange,								// VkImageSubresourceRange	subresourceRange;
    228 	};
    229 	return createImageView(vk, vkDevice, &imageViewParams);
    230 }
    231 
    232 VkBufferImageCopy makeBufferImageCopy (const VkExtent3D					extent,
    233 									   const VkImageSubresourceLayers	subresourceLayers)
    234 {
    235 	const VkBufferImageCopy copyParams =
    236 	{
    237 		0ull,										//	VkDeviceSize				bufferOffset;
    238 		0u,											//	deUint32					bufferRowLength;
    239 		0u,											//	deUint32					bufferImageHeight;
    240 		subresourceLayers,							//	VkImageSubresourceLayers	imageSubresource;
    241 		makeOffset3D(0, 0, 0),						//	VkOffset3D					imageOffset;
    242 		extent,										//	VkExtent3D					imageExtent;
    243 	};
    244 	return copyParams;
    245 }
    246 
    247 void beginCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer)
    248 {
    249 	const VkCommandBufferBeginInfo info =
    250 	{
    251 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,	// VkStructureType                          sType;
    252 		DE_NULL,										// const void*                              pNext;
    253 		VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,	// VkCommandBufferUsageFlags                flags;
    254 		DE_NULL,										// const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
    255 	};
    256 	VK_CHECK(vk.beginCommandBuffer(commandBuffer, &info));
    257 }
    258 
    259 void endCommandBuffer (const DeviceInterface& vk, const VkCommandBuffer commandBuffer)
    260 {
    261 	VK_CHECK(vk.endCommandBuffer(commandBuffer));
    262 }
    263 
    264 void submitCommandsAndWait (const DeviceInterface&	vk,
    265 							const VkDevice			device,
    266 							const VkQueue			queue,
    267 							const VkCommandBuffer	commandBuffer)
    268 {
    269 	const Unique<VkFence> fence(createFence(vk, device));
    270 
    271 	const VkSubmitInfo submitInfo =
    272 	{
    273 		VK_STRUCTURE_TYPE_SUBMIT_INFO,		// VkStructureType                sType;
    274 		DE_NULL,							// const void*                    pNext;
    275 		0u,									// uint32_t                       waitSemaphoreCount;
    276 		DE_NULL,							// const VkSemaphore*             pWaitSemaphores;
    277 		DE_NULL,							// const VkPipelineStageFlags*    pWaitDstStageMask;
    278 		1u,									// uint32_t                       commandBufferCount;
    279 		&commandBuffer,						// const VkCommandBuffer*         pCommandBuffers;
    280 		0u,									// uint32_t                       signalSemaphoreCount;
    281 		DE_NULL,							// const VkSemaphore*             pSignalSemaphores;
    282 	};
    283 	VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
    284 	VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), DE_TRUE, ~0ull));
    285 }
    286 
    287 void beginRenderPass (const DeviceInterface&	vk,
    288 					  const VkCommandBuffer		commandBuffer,
    289 					  const VkRenderPass		renderPass,
    290 					  const VkFramebuffer		framebuffer,
    291 					  const VkRect2D&			renderArea,
    292 					  const tcu::Vec4&			clearColor)
    293 {
    294 	const VkClearValue clearValue = makeClearValueColor(clearColor);
    295 
    296 	const VkRenderPassBeginInfo renderPassBeginInfo = {
    297 		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
    298 		DE_NULL,										// const void*             pNext;
    299 		renderPass,										// VkRenderPass            renderPass;
    300 		framebuffer,									// VkFramebuffer           framebuffer;
    301 		renderArea,										// VkRect2D                renderArea;
    302 		1u,												// uint32_t                clearValueCount;
    303 		&clearValue,									// const VkClearValue*     pClearValues;
    304 	};
    305 
    306 	vk.cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    307 }
    308 
    309 void beginRenderPassWithRasterizationDisabled (const DeviceInterface&	vk,
    310 											   const VkCommandBuffer	commandBuffer,
    311 											   const VkRenderPass		renderPass,
    312 											   const VkFramebuffer		framebuffer)
    313 {
    314 	const VkRect2D renderArea = {{ 0, 0 }, { 0, 0 }};
    315 
    316 	const VkRenderPassBeginInfo renderPassBeginInfo = {
    317 		VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
    318 		DE_NULL,										// const void*             pNext;
    319 		renderPass,										// VkRenderPass            renderPass;
    320 		framebuffer,									// VkFramebuffer           framebuffer;
    321 		renderArea,										// VkRect2D                renderArea;
    322 		0u,												// uint32_t                clearValueCount;
    323 		DE_NULL,										// const VkClearValue*     pClearValues;
    324 	};
    325 
    326 	vk.cmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    327 }
    328 
    329 void endRenderPass (const DeviceInterface&	vk,
    330 					const VkCommandBuffer	commandBuffer)
    331 {
    332 	vk.cmdEndRenderPass(commandBuffer);
    333 }
    334 
    335 Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
    336 								   const VkDevice			device,
    337 								   const VkFormat			colorFormat)
    338 {
    339 	const VkAttachmentDescription colorAttachmentDescription =
    340 	{
    341 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
    342 		colorFormat,										// VkFormat							format;
    343 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
    344 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
    345 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
    346 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
    347 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
    348 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					initialLayout;
    349 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout					finalLayout;
    350 	};
    351 
    352 	const VkAttachmentReference colorAttachmentReference =
    353 	{
    354 		0u,													// deUint32			attachment;
    355 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
    356 	};
    357 
    358 	const VkAttachmentReference depthAttachmentReference =
    359 	{
    360 		VK_ATTACHMENT_UNUSED,								// deUint32			attachment;
    361 		VK_IMAGE_LAYOUT_UNDEFINED							// VkImageLayout	layout;
    362 	};
    363 
    364 	const VkSubpassDescription subpassDescription =
    365 	{
    366 		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
    367 		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
    368 		0u,													// deUint32							inputAttachmentCount;
    369 		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
    370 		1u,													// deUint32							colorAttachmentCount;
    371 		&colorAttachmentReference,							// const VkAttachmentReference*		pColorAttachments;
    372 		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
    373 		&depthAttachmentReference,							// const VkAttachmentReference*		pDepthStencilAttachment;
    374 		0u,													// deUint32							preserveAttachmentCount;
    375 		DE_NULL												// const deUint32*					pPreserveAttachments;
    376 	};
    377 
    378 	const VkRenderPassCreateInfo renderPassInfo =
    379 	{
    380 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
    381 		DE_NULL,											// const void*						pNext;
    382 		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
    383 		1u,													// deUint32							attachmentCount;
    384 		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
    385 		1u,													// deUint32							subpassCount;
    386 		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
    387 		0u,													// deUint32							dependencyCount;
    388 		DE_NULL												// const VkSubpassDependency*		pDependencies;
    389 	};
    390 
    391 	return createRenderPass(vk, device, &renderPassInfo);
    392 }
    393 
    394 Move<VkRenderPass> makeRenderPassWithoutAttachments (const DeviceInterface&	vk,
    395 													 const VkDevice			device)
    396 {
    397 	const VkAttachmentReference unusedAttachment =
    398 	{
    399 		VK_ATTACHMENT_UNUSED,								// deUint32			attachment;
    400 		VK_IMAGE_LAYOUT_UNDEFINED							// VkImageLayout	layout;
    401 	};
    402 
    403 	const VkSubpassDescription subpassDescription =
    404 	{
    405 		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
    406 		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
    407 		0u,													// deUint32							inputAttachmentCount;
    408 		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
    409 		0u,													// deUint32							colorAttachmentCount;
    410 		DE_NULL,											// const VkAttachmentReference*		pColorAttachments;
    411 		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
    412 		&unusedAttachment,									// const VkAttachmentReference*		pDepthStencilAttachment;
    413 		0u,													// deUint32							preserveAttachmentCount;
    414 		DE_NULL												// const deUint32*					pPreserveAttachments;
    415 	};
    416 
    417 	const VkRenderPassCreateInfo renderPassInfo =
    418 	{
    419 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
    420 		DE_NULL,											// const void*						pNext;
    421 		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
    422 		0u,													// deUint32							attachmentCount;
    423 		DE_NULL,											// const VkAttachmentDescription*	pAttachments;
    424 		1u,													// deUint32							subpassCount;
    425 		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
    426 		0u,													// deUint32							dependencyCount;
    427 		DE_NULL												// const VkSubpassDependency*		pDependencies;
    428 	};
    429 
    430 	return createRenderPass(vk, device, &renderPassInfo);
    431 }
    432 
    433 Move<VkFramebuffer> makeFramebuffer (const DeviceInterface&		vk,
    434 									 const VkDevice				device,
    435 									 const VkRenderPass			renderPass,
    436 									 const VkImageView			colorAttachment,
    437 									 const deUint32				width,
    438 									 const deUint32				height,
    439 									 const deUint32				layers)
    440 {
    441 	const VkFramebufferCreateInfo framebufferInfo = {
    442 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
    443 		DE_NULL,										// const void*                                 pNext;
    444 		(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
    445 		renderPass,										// VkRenderPass                                renderPass;
    446 		1u,												// uint32_t                                    attachmentCount;
    447 		&colorAttachment,								// const VkImageView*                          pAttachments;
    448 		width,											// uint32_t                                    width;
    449 		height,											// uint32_t                                    height;
    450 		layers,											// uint32_t                                    layers;
    451 	};
    452 
    453 	return createFramebuffer(vk, device, &framebufferInfo);
    454 }
    455 
    456 Move<VkFramebuffer> makeFramebufferWithoutAttachments (const DeviceInterface&		vk,
    457 													   const VkDevice				device,
    458 													   const VkRenderPass			renderPass)
    459 {
    460 	const VkFramebufferCreateInfo framebufferInfo = {
    461 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
    462 		DE_NULL,										// const void*                                 pNext;
    463 		(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
    464 		renderPass,										// VkRenderPass                                renderPass;
    465 		0u,												// uint32_t                                    attachmentCount;
    466 		DE_NULL,										// const VkImageView*                          pAttachments;
    467 		1u,												// uint32_t                                    width;
    468 		1u,												// uint32_t                                    height;
    469 		1u,												// uint32_t                                    layers;
    470 	};
    471 
    472 	return createFramebuffer(vk, device, &framebufferInfo);
    473 }
    474 
    475 GraphicsPipelineBuilder& GraphicsPipelineBuilder::setShader (const DeviceInterface&			vk,
    476 															 const VkDevice					device,
    477 															 const VkShaderStageFlagBits	stage,
    478 															 const ProgramBinary&			binary,
    479 															 const VkSpecializationInfo*	specInfo)
    480 {
    481 	VkShaderModule module;
    482 	switch (stage)
    483 	{
    484 		case (VK_SHADER_STAGE_VERTEX_BIT):
    485 			DE_ASSERT(m_vertexShaderModule.get() == DE_NULL);
    486 			m_vertexShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
    487 			module = *m_vertexShaderModule;
    488 			break;
    489 
    490 		case (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT):
    491 			DE_ASSERT(m_tessControlShaderModule.get() == DE_NULL);
    492 			m_tessControlShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
    493 			module = *m_tessControlShaderModule;
    494 			break;
    495 
    496 		case (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT):
    497 			DE_ASSERT(m_tessEvaluationShaderModule.get() == DE_NULL);
    498 			m_tessEvaluationShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
    499 			module = *m_tessEvaluationShaderModule;
    500 			break;
    501 
    502 		case (VK_SHADER_STAGE_GEOMETRY_BIT):
    503 			DE_ASSERT(m_geometryShaderModule.get() == DE_NULL);
    504 			m_geometryShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
    505 			module = *m_geometryShaderModule;
    506 			break;
    507 
    508 		case (VK_SHADER_STAGE_FRAGMENT_BIT):
    509 			DE_ASSERT(m_fragmentShaderModule.get() == DE_NULL);
    510 			m_fragmentShaderModule = createShaderModule(vk, device, binary, (VkShaderModuleCreateFlags)0);
    511 			module = *m_fragmentShaderModule;
    512 			break;
    513 
    514 		default:
    515 			DE_FATAL("Invalid shader stage");
    516 			return *this;
    517 	}
    518 
    519 	const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo =
    520 	{
    521 		VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
    522 		DE_NULL,												// const void*							pNext;
    523 		(VkPipelineShaderStageCreateFlags)0,					// VkPipelineShaderStageCreateFlags		flags;
    524 		stage,													// VkShaderStageFlagBits				stage;
    525 		module,													// VkShaderModule						module;
    526 		"main",													// const char*							pName;
    527 		specInfo,												// const VkSpecializationInfo*			pSpecializationInfo;
    528 	};
    529 
    530 	m_shaderStageFlags |= stage;
    531 	m_shaderStages.push_back(pipelineShaderStageInfo);
    532 
    533 	return *this;
    534 }
    535 
    536 GraphicsPipelineBuilder& GraphicsPipelineBuilder::setVertexInputSingleAttribute (const VkFormat vertexFormat, const deUint32 stride)
    537 {
    538 	const VkVertexInputBindingDescription bindingDesc =
    539 	{
    540 		0u,									// uint32_t				binding;
    541 		stride,								// uint32_t				stride;
    542 		VK_VERTEX_INPUT_RATE_VERTEX,		// VkVertexInputRate	inputRate;
    543 	};
    544 	const VkVertexInputAttributeDescription attributeDesc =
    545 	{
    546 		0u,									// uint32_t			location;
    547 		0u,									// uint32_t			binding;
    548 		vertexFormat,						// VkFormat			format;
    549 		0u,									// uint32_t			offset;
    550 	};
    551 
    552 	m_vertexInputBindings.clear();
    553 	m_vertexInputBindings.push_back(bindingDesc);
    554 
    555 	m_vertexInputAttributes.clear();
    556 	m_vertexInputAttributes.push_back(attributeDesc);
    557 
    558 	return *this;
    559 }
    560 
    561 template<typename T>
    562 inline const T* dataPointer (const std::vector<T>& vec)
    563 {
    564 	return (vec.size() != 0 ? &vec[0] : DE_NULL);
    565 }
    566 
    567 Move<VkPipeline> GraphicsPipelineBuilder::build (const DeviceInterface&	vk,
    568 												 const VkDevice			device,
    569 												 const VkPipelineLayout	pipelineLayout,
    570 												 const VkRenderPass		renderPass)
    571 {
    572 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
    573 	{
    574 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
    575 		DE_NULL,														// const void*                                 pNext;
    576 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
    577 		static_cast<deUint32>(m_vertexInputBindings.size()),			// uint32_t                                    vertexBindingDescriptionCount;
    578 		dataPointer(m_vertexInputBindings),								// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    579 		static_cast<deUint32>(m_vertexInputAttributes.size()),			// uint32_t                                    vertexAttributeDescriptionCount;
    580 		dataPointer(m_vertexInputAttributes),							// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
    581 	};
    582 
    583 	const VkPrimitiveTopology topology = (m_shaderStageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
    584 																										 : m_primitiveTopology;
    585 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
    586 	{
    587 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
    588 		DE_NULL,														// const void*                                 pNext;
    589 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
    590 		topology,														// VkPrimitiveTopology                         topology;
    591 		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
    592 	};
    593 
    594 	const VkPipelineTessellationDomainOriginStateCreateInfo tessellationDomainOriginStateInfo =
    595 	{
    596 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO,
    597 		DE_NULL,
    598 		(!m_tessellationDomainOrigin ? VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT : *m_tessellationDomainOrigin)
    599 	};
    600 	const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
    601 	{
    602 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType                             sType;
    603 		(!m_tessellationDomainOrigin ? DE_NULL : &tessellationDomainOriginStateInfo),
    604 		(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags      flags;
    605 		m_patchControlPoints,											// uint32_t                                    patchControlPoints;
    606 	};
    607 
    608 	const VkViewport viewport = makeViewport(
    609 		0.0f, 0.0f,
    610 		static_cast<float>(m_renderSize.x()), static_cast<float>(m_renderSize.y()),
    611 		0.0f, 1.0f);
    612 
    613 	const VkRect2D scissor = {
    614 		makeOffset2D(0, 0),
    615 		makeExtent2D(m_renderSize.x(), m_renderSize.y()),
    616 	};
    617 
    618 	const bool haveRenderSize = m_renderSize.x() > 0 && m_renderSize.y() > 0;
    619 
    620 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
    621 	{
    622 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	// VkStructureType                             sType;
    623 		DE_NULL,												// const void*                                 pNext;
    624 		(VkPipelineViewportStateCreateFlags)0,					// VkPipelineViewportStateCreateFlags          flags;
    625 		1u,														// uint32_t                                    viewportCount;
    626 		haveRenderSize ? &viewport : DE_NULL,					// const VkViewport*                           pViewports;
    627 		1u,														// uint32_t                                    scissorCount;
    628 		haveRenderSize ? &scissor : DE_NULL,					// const VkRect2D*                             pScissors;
    629 	};
    630 
    631 	const bool isRasterizationDisabled = ((m_shaderStageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) == 0);
    632 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
    633 	{
    634 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
    635 		DE_NULL,														// const void*                              pNext;
    636 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
    637 		VK_FALSE,														// VkBool32                                 depthClampEnable;
    638 		isRasterizationDisabled,										// VkBool32                                 rasterizerDiscardEnable;
    639 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
    640 		m_cullModeFlags,												// VkCullModeFlags							cullMode;
    641 		m_frontFace,													// VkFrontFace								frontFace;
    642 		VK_FALSE,														// VkBool32									depthBiasEnable;
    643 		0.0f,															// float									depthBiasConstantFactor;
    644 		0.0f,															// float									depthBiasClamp;
    645 		0.0f,															// float									depthBiasSlopeFactor;
    646 		1.0f,															// float									lineWidth;
    647 	};
    648 
    649 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
    650 	{
    651 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
    652 		DE_NULL,													// const void*								pNext;
    653 		(VkPipelineMultisampleStateCreateFlags)0,					// VkPipelineMultisampleStateCreateFlags	flags;
    654 		VK_SAMPLE_COUNT_1_BIT,										// VkSampleCountFlagBits					rasterizationSamples;
    655 		VK_FALSE,													// VkBool32									sampleShadingEnable;
    656 		0.0f,														// float									minSampleShading;
    657 		DE_NULL,													// const VkSampleMask*						pSampleMask;
    658 		VK_FALSE,													// VkBool32									alphaToCoverageEnable;
    659 		VK_FALSE													// VkBool32									alphaToOneEnable;
    660 	};
    661 
    662 	const VkStencilOpState stencilOpState = makeStencilOpState(
    663 		VK_STENCIL_OP_KEEP,		// stencil fail
    664 		VK_STENCIL_OP_KEEP,		// depth & stencil pass
    665 		VK_STENCIL_OP_KEEP,		// depth only fail
    666 		VK_COMPARE_OP_NEVER,	// compare op
    667 		0u,						// compare mask
    668 		0u,						// write mask
    669 		0u);					// reference
    670 
    671 	const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
    672 	{
    673 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
    674 		DE_NULL,													// const void*								pNext;
    675 		(VkPipelineDepthStencilStateCreateFlags)0,					// VkPipelineDepthStencilStateCreateFlags	flags;
    676 		VK_FALSE,													// VkBool32									depthTestEnable;
    677 		VK_FALSE,													// VkBool32									depthWriteEnable;
    678 		VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
    679 		VK_FALSE,													// VkBool32									depthBoundsTestEnable;
    680 		VK_FALSE,													// VkBool32									stencilTestEnable;
    681 		stencilOpState,												// VkStencilOpState							front;
    682 		stencilOpState,												// VkStencilOpState							back;
    683 		0.0f,														// float									minDepthBounds;
    684 		1.0f,														// float									maxDepthBounds;
    685 	};
    686 
    687 	const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    688 	const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
    689 	{
    690 		m_blendEnable,						// VkBool32					blendEnable;
    691 		VK_BLEND_FACTOR_SRC_ALPHA,			// VkBlendFactor			srcColorBlendFactor;
    692 		VK_BLEND_FACTOR_ONE,				// VkBlendFactor			dstColorBlendFactor;
    693 		VK_BLEND_OP_ADD,					// VkBlendOp				colorBlendOp;
    694 		VK_BLEND_FACTOR_SRC_ALPHA,			// VkBlendFactor			srcAlphaBlendFactor;
    695 		VK_BLEND_FACTOR_ONE,				// VkBlendFactor			dstAlphaBlendFactor;
    696 		VK_BLEND_OP_ADD,					// VkBlendOp				alphaBlendOp;
    697 		colorComponentsAll,					// VkColorComponentFlags	colorWriteMask;
    698 	};
    699 
    700 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
    701 	{
    702 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
    703 		DE_NULL,													// const void*									pNext;
    704 		(VkPipelineColorBlendStateCreateFlags)0,					// VkPipelineColorBlendStateCreateFlags			flags;
    705 		VK_FALSE,													// VkBool32										logicOpEnable;
    706 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
    707 		1u,															// deUint32										attachmentCount;
    708 		&pipelineColorBlendAttachmentState,							// const VkPipelineColorBlendAttachmentState*	pAttachments;
    709 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConstants[4];
    710 	};
    711 
    712 	std::vector<VkDynamicState> dynamicStates;
    713 	if (!haveRenderSize && !isRasterizationDisabled)
    714 	{
    715 		dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
    716 		dynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR);
    717 	}
    718 
    719 	const VkPipelineDynamicStateCreateInfo pipelineDynamicStateInfo =
    720 	{
    721 		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	// VkStructureType						sType;
    722 		DE_NULL,												// const void*							pNext;
    723 		0,														// VkPipelineDynamicStateCreateFlags	flags;
    724 		static_cast<deUint32>(dynamicStates.size()),			// uint32_t								dynamicStateCount;
    725 		(dynamicStates.empty() ? DE_NULL : &dynamicStates[0]),	// const VkDynamicState*				pDynamicStates;
    726 	};
    727 
    728 	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
    729 	{
    730 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,						// VkStructureType									sType;
    731 		DE_NULL,																// const void*										pNext;
    732 		(VkPipelineCreateFlags)0,												// VkPipelineCreateFlags							flags;
    733 		static_cast<deUint32>(m_shaderStages.size()),							// deUint32											stageCount;
    734 		&m_shaderStages[0],														// const VkPipelineShaderStageCreateInfo*			pStages;
    735 		&vertexInputStateInfo,													// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
    736 		&pipelineInputAssemblyStateInfo,										// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
    737 		(m_shaderStageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ? &pipelineTessellationStateInfo : DE_NULL), // const VkPipelineTessellationStateCreateInfo*		pTessellationState;
    738 		(isRasterizationDisabled ? DE_NULL : &pipelineViewportStateInfo),		// const VkPipelineViewportStateCreateInfo*			pViewportState;
    739 		&pipelineRasterizationStateInfo,										// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
    740 		(isRasterizationDisabled ? DE_NULL : &pipelineMultisampleStateInfo),	// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
    741 		(isRasterizationDisabled ? DE_NULL : &pipelineDepthStencilStateInfo),	// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
    742 		(isRasterizationDisabled ? DE_NULL : &pipelineColorBlendStateInfo),		// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
    743 		(dynamicStates.empty() ? DE_NULL : &pipelineDynamicStateInfo),			// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
    744 		pipelineLayout,															// VkPipelineLayout									layout;
    745 		renderPass,																// VkRenderPass										renderPass;
    746 		0u,																		// deUint32											subpass;
    747 		DE_NULL,																// VkPipeline										basePipelineHandle;
    748 		0,																		// deInt32											basePipelineIndex;
    749 	};
    750 
    751 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
    752 }
    753 
    754 float getClampedTessLevel (const SpacingMode mode, const float tessLevel)
    755 {
    756 	switch (mode)
    757 	{
    758 		case SPACINGMODE_EQUAL:				return de::max(1.0f, tessLevel);
    759 		case SPACINGMODE_FRACTIONAL_ODD:	return de::max(1.0f, tessLevel);
    760 		case SPACINGMODE_FRACTIONAL_EVEN:	return de::max(2.0f, tessLevel);
    761 		default:
    762 			DE_ASSERT(false);
    763 			return 0.0f;
    764 	}
    765 }
    766 
    767 int getRoundedTessLevel (const SpacingMode mode, const float clampedTessLevel)
    768 {
    769 	static const int minimumMaxTessGenLevel = 64;	//!< Minimum maxTessellationGenerationLevel defined by the spec.
    770 
    771 	int result = (int)deFloatCeil(clampedTessLevel);
    772 
    773 	switch (mode)
    774 	{
    775 		case SPACINGMODE_EQUAL:											break;
    776 		case SPACINGMODE_FRACTIONAL_ODD:	result += 1 - result % 2;	break;
    777 		case SPACINGMODE_FRACTIONAL_EVEN:	result += result % 2;		break;
    778 		default:
    779 			DE_ASSERT(false);
    780 	}
    781 	DE_ASSERT(de::inRange<int>(result, 1, minimumMaxTessGenLevel));
    782 	DE_UNREF(minimumMaxTessGenLevel);
    783 
    784 	return result;
    785 }
    786 
    787 int getClampedRoundedTessLevel (const SpacingMode mode, const float tessLevel)
    788 {
    789 	return getRoundedTessLevel(mode, getClampedTessLevel(mode, tessLevel));
    790 }
    791 
    792 void getClampedRoundedTriangleTessLevels (const SpacingMode	spacingMode,
    793 										  const float*		innerSrc,
    794 										  const float*		outerSrc,
    795 										  int*				innerDst,
    796 										  int*				outerDst)
    797 {
    798 	innerDst[0] = getClampedRoundedTessLevel(spacingMode, innerSrc[0]);
    799 	for (int i = 0; i < 3; i++)
    800 		outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
    801 }
    802 
    803 void getClampedRoundedQuadTessLevels (const SpacingMode spacingMode,
    804 									  const float*		innerSrc,
    805 									  const float*		outerSrc,
    806 									  int*				innerDst,
    807 									  int*				outerDst)
    808 {
    809 	for (int i = 0; i < 2; i++)
    810 		innerDst[i] = getClampedRoundedTessLevel(spacingMode, innerSrc[i]);
    811 	for (int i = 0; i < 4; i++)
    812 		outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
    813 }
    814 
    815 void getClampedRoundedIsolineTessLevels (const SpacingMode	spacingMode,
    816 										 const float*		outerSrc,
    817 										 int*				outerDst)
    818 {
    819 	outerDst[0] = getClampedRoundedTessLevel(SPACINGMODE_EQUAL,	outerSrc[0]);
    820 	outerDst[1] = getClampedRoundedTessLevel(spacingMode,		outerSrc[1]);
    821 }
    822 
    823 int numOuterTessellationLevels (const TessPrimitiveType primType)
    824 {
    825 	switch (primType)
    826 	{
    827 		case TESSPRIMITIVETYPE_TRIANGLES:	return 3;
    828 		case TESSPRIMITIVETYPE_QUADS:		return 4;
    829 		case TESSPRIMITIVETYPE_ISOLINES:	return 2;
    830 		default:
    831 			DE_ASSERT(false);
    832 			return 0;
    833 	}
    834 }
    835 
    836 bool isPatchDiscarded (const TessPrimitiveType primitiveType, const float* outerLevels)
    837 {
    838 	const int numOuterLevels = numOuterTessellationLevels(primitiveType);
    839 	for (int i = 0; i < numOuterLevels; i++)
    840 		if (outerLevels[i] <= 0.0f)
    841 			return true;
    842 	return false;
    843 }
    844 
    845 std::string getTessellationLevelsString (const TessLevels& tessLevels, const TessPrimitiveType primitiveType)
    846 {
    847 	std::ostringstream str;
    848 	switch (primitiveType)
    849 	{
    850 		case TESSPRIMITIVETYPE_ISOLINES:
    851 			str << "inner: { }, "
    852 				<< "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << " }";
    853 			break;
    854 
    855 		case TESSPRIMITIVETYPE_TRIANGLES:
    856 			str << "inner: { " << tessLevels.inner[0] << " }, "
    857 				<< "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << ", " << tessLevels.outer[2] << " }";
    858 			break;
    859 
    860 		case TESSPRIMITIVETYPE_QUADS:
    861 			str << "inner: { " << tessLevels.inner[0] << ", " << tessLevels.inner[1] << " }, "
    862 				<< "outer: { " << tessLevels.outer[0] << ", " << tessLevels.outer[1] << ", " << tessLevels.outer[2] << ", " << tessLevels.outer[3] << " }";
    863 			break;
    864 
    865 		default:
    866 			DE_ASSERT(false);
    867 	}
    868 
    869 	return str.str();
    870 }
    871 
    872 //! Assumes array sizes inner[2] and outer[4].
    873 std::string getTessellationLevelsString (const float* inner, const float* outer)
    874 {
    875 	const TessLevels tessLevels =
    876 	{
    877 		{ inner[0], inner[1] },
    878 		{ outer[0], outer[1], outer[2], outer[3] }
    879 	};
    880 	return getTessellationLevelsString(tessLevels, TESSPRIMITIVETYPE_QUADS);
    881 }
    882 
    883 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
    884 // (e.g. it may not exactly hold that u+v+w == 1.0f, or [uvw] + (1.0f-[uvw]) == 1.0f).
    885 std::vector<tcu::Vec3> generateReferenceTriangleTessCoords (const SpacingMode	spacingMode,
    886 															const int			inner,
    887 															const int			outer0,
    888 															const int			outer1,
    889 															const int			outer2)
    890 {
    891 	std::vector<tcu::Vec3> tessCoords;
    892 
    893 	if (inner == 1)
    894 	{
    895 		if (outer0 == 1 && outer1 == 1 && outer2 == 1)
    896 		{
    897 			tessCoords.push_back(tcu::Vec3(1.0f, 0.0f, 0.0f));
    898 			tessCoords.push_back(tcu::Vec3(0.0f, 1.0f, 0.0f));
    899 			tessCoords.push_back(tcu::Vec3(0.0f, 0.0f, 1.0f));
    900 			return tessCoords;
    901 		}
    902 		else
    903 			return generateReferenceTriangleTessCoords(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
    904 													   outer0, outer1, outer2);
    905 	}
    906 	else
    907 	{
    908 		for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(tcu::Vec3(    0.0f,        v, 1.0f - v)); }
    909 		for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(tcu::Vec3(1.0f - v,     0.0f,        v)); }
    910 		for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(tcu::Vec3(       v, 1.0f - v,     0.0f)); }
    911 
    912 		const int numInnerTriangles = inner/2;
    913 		for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
    914 		{
    915 			const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
    916 
    917 			if (curInnerTriangleLevel == 0)
    918 				tessCoords.push_back(tcu::Vec3(1.0f/3.0f));
    919 			else
    920 			{
    921 				const float		minUVW		= (float)(2 * (innerTriangleNdx + 1)) / (float)(3 * inner);
    922 				const float		maxUVW		= 1.0f - 2.0f*minUVW;
    923 				const tcu::Vec3	corners[3]	=
    924 				{
    925 					tcu::Vec3(maxUVW, minUVW, minUVW),
    926 					tcu::Vec3(minUVW, maxUVW, minUVW),
    927 					tcu::Vec3(minUVW, minUVW, maxUVW)
    928 				};
    929 
    930 				for (int i = 0; i < curInnerTriangleLevel; i++)
    931 				{
    932 					const float f = (float)i / (float)curInnerTriangleLevel;
    933 					for (int j = 0; j < 3; j++)
    934 						tessCoords.push_back((1.0f - f)*corners[j] + f*corners[(j+1)%3]);
    935 				}
    936 			}
    937 		}
    938 
    939 		return tessCoords;
    940 	}
    941 }
    942 
    943 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
    944 // (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
    945 std::vector<tcu::Vec3> generateReferenceQuadTessCoords (const SpacingMode	spacingMode,
    946 														const int			inner0,
    947 														const int			inner1,
    948 														const int			outer0,
    949 														const int			outer1,
    950 														const int			outer2,
    951 														const int			outer3)
    952 {
    953 	std::vector<tcu::Vec3> tessCoords;
    954 
    955 	if (inner0 == 1 || inner1 == 1)
    956 	{
    957 		if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
    958 		{
    959 			tessCoords.push_back(tcu::Vec3(0.0f, 0.0f, 0.0f));
    960 			tessCoords.push_back(tcu::Vec3(1.0f, 0.0f, 0.0f));
    961 			tessCoords.push_back(tcu::Vec3(0.0f, 1.0f, 0.0f));
    962 			tessCoords.push_back(tcu::Vec3(1.0f, 1.0f, 0.0f));
    963 			return tessCoords;
    964 		}
    965 		else
    966 			return generateReferenceQuadTessCoords(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
    967 																inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
    968 																outer0, outer1, outer2, outer3);
    969 	}
    970 	else
    971 	{
    972 		for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(tcu::Vec3(    0.0f,        v, 0.0f)); }
    973 		for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(tcu::Vec3(1.0f - v,     0.0f, 0.0f)); }
    974 		for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(tcu::Vec3(    1.0f, 1.0f - v, 0.0f)); }
    975 		for (int i = 0; i < outer3; i++) { const float v = (float)i / (float)outer3; tessCoords.push_back(tcu::Vec3(       v,     1.0f, 0.0f)); }
    976 
    977 		for (int innerVtxY = 0; innerVtxY < inner1-1; innerVtxY++)
    978 		for (int innerVtxX = 0; innerVtxX < inner0-1; innerVtxX++)
    979 			tessCoords.push_back(tcu::Vec3((float)(innerVtxX + 1) / (float)inner0,
    980 										   (float)(innerVtxY + 1) / (float)inner1,
    981 										   0.0f));
    982 
    983 		return tessCoords;
    984 	}
    985 }
    986 
    987 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec
    988 // (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
    989 std::vector<tcu::Vec3> generateReferenceIsolineTessCoords (const int outer0, const int outer1)
    990 {
    991 	std::vector<tcu::Vec3> tessCoords;
    992 
    993 	for (int y = 0; y < outer0;   y++)
    994 	for (int x = 0; x < outer1+1; x++)
    995 		tessCoords.push_back(tcu::Vec3((float)x / (float)outer1,
    996 									   (float)y / (float)outer0,
    997 									   0.0f));
    998 
    999 	return tessCoords;
   1000 }
   1001 
   1002 static int referencePointModePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
   1003 {
   1004 	if (isPatchDiscarded(primitiveType, outerLevels))
   1005 		return 0;
   1006 
   1007 	switch (primitiveType)
   1008 	{
   1009 		case TESSPRIMITIVETYPE_TRIANGLES:
   1010 		{
   1011 			int inner;
   1012 			int outer[3];
   1013 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
   1014 			return static_cast<int>(generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]).size());
   1015 		}
   1016 
   1017 		case TESSPRIMITIVETYPE_QUADS:
   1018 		{
   1019 			int inner[2];
   1020 			int outer[4];
   1021 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
   1022 			return static_cast<int>(generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]).size());
   1023 		}
   1024 
   1025 		case TESSPRIMITIVETYPE_ISOLINES:
   1026 		{
   1027 			int outer[2];
   1028 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
   1029 			return static_cast<int>(generateReferenceIsolineTessCoords(outer[0], outer[1]).size());
   1030 		}
   1031 
   1032 		default:
   1033 			DE_ASSERT(false);
   1034 			return 0;
   1035 	}
   1036 }
   1037 
   1038 static int referenceTriangleNonPointModePrimitiveCount (const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2)
   1039 {
   1040 	if (inner == 1)
   1041 	{
   1042 		if (outer0 == 1 && outer1 == 1 && outer2 == 1)
   1043 			return 1;
   1044 		else
   1045 			return referenceTriangleNonPointModePrimitiveCount(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
   1046 																			outer0, outer1, outer2);
   1047 	}
   1048 	else
   1049 	{
   1050 		int result = outer0 + outer1 + outer2;
   1051 
   1052 		const int numInnerTriangles = inner/2;
   1053 		for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
   1054 		{
   1055 			const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
   1056 
   1057 			if (curInnerTriangleLevel == 1)
   1058 				result += 4;
   1059 			else
   1060 				result += 2*3*curInnerTriangleLevel;
   1061 		}
   1062 
   1063 		return result;
   1064 	}
   1065 }
   1066 
   1067 static int referenceQuadNonPointModePrimitiveCount (const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3)
   1068 {
   1069 	if (inner0 == 1 || inner1 == 1)
   1070 	{
   1071 		if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
   1072 			return 2;
   1073 		else
   1074 			return referenceQuadNonPointModePrimitiveCount(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
   1075 																		inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
   1076 																		outer0, outer1, outer2, outer3);
   1077 	}
   1078 	else
   1079 		return 2*(inner0-2)*(inner1-2) + 2*(inner0-2) + 2*(inner1-2) + outer0+outer1+outer2+outer3;
   1080 }
   1081 
   1082 static inline int referenceIsolineNonPointModePrimitiveCount (const int outer0, const int outer1)
   1083 {
   1084 	return outer0*outer1;
   1085 }
   1086 
   1087 static int referenceNonPointModePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
   1088 {
   1089 	if (isPatchDiscarded(primitiveType, outerLevels))
   1090 		return 0;
   1091 
   1092 	switch (primitiveType)
   1093 	{
   1094 		case TESSPRIMITIVETYPE_TRIANGLES:
   1095 		{
   1096 			int inner;
   1097 			int outer[3];
   1098 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
   1099 			return referenceTriangleNonPointModePrimitiveCount(spacingMode, inner, outer[0], outer[1], outer[2]);
   1100 		}
   1101 
   1102 		case TESSPRIMITIVETYPE_QUADS:
   1103 		{
   1104 			int inner[2];
   1105 			int outer[4];
   1106 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
   1107 			return referenceQuadNonPointModePrimitiveCount(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
   1108 		}
   1109 
   1110 		case TESSPRIMITIVETYPE_ISOLINES:
   1111 		{
   1112 			int outer[2];
   1113 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
   1114 			return referenceIsolineNonPointModePrimitiveCount(outer[0], outer[1]);
   1115 		}
   1116 
   1117 		default:
   1118 			DE_ASSERT(false);
   1119 			return 0;
   1120 	}
   1121 }
   1122 
   1123 int numVerticesPerPrimitive (const TessPrimitiveType primitiveType, const bool usePointMode)
   1124 {
   1125 	if (usePointMode)
   1126 		return 1;
   1127 
   1128 	switch (primitiveType)
   1129 	{
   1130 		case TESSPRIMITIVETYPE_TRIANGLES:	return 3;
   1131 		case TESSPRIMITIVETYPE_QUADS:		return 3;  // quads are composed of two triangles
   1132 		case TESSPRIMITIVETYPE_ISOLINES:	return 2;
   1133 		default:
   1134 			DE_ASSERT(false);
   1135 			return 0;
   1136 	}
   1137 }
   1138 
   1139 int referencePrimitiveCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)
   1140 {
   1141 	return usePointMode ? referencePointModePrimitiveCount		(primitiveType, spacingMode, innerLevels, outerLevels)
   1142 						: referenceNonPointModePrimitiveCount	(primitiveType, spacingMode, innerLevels, outerLevels);
   1143 }
   1144 
   1145 //! In point mode this should return the number of unique vertices, while in non-point mode the maximum theoretical number of verticies.
   1146 //! Actual implementation will likely return a much smaller number because the shader isn't required to be run for duplicate coordinates.
   1147 int referenceVertexCount (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels)
   1148 {
   1149 	return referencePrimitiveCount(primitiveType, spacingMode, usePointMode, innerLevels, outerLevels)
   1150 		   * numVerticesPerPrimitive(primitiveType, usePointMode);
   1151 }
   1152 
   1153 void requireFeatures (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const FeatureFlags flags)
   1154 {
   1155 	const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice);
   1156 
   1157 	if (((flags & FEATURE_TESSELLATION_SHADER) != 0) && !features.tessellationShader)
   1158 		throw tcu::NotSupportedError("Tessellation shader not supported");
   1159 
   1160 	if (((flags & FEATURE_GEOMETRY_SHADER) != 0) && !features.geometryShader)
   1161 		throw tcu::NotSupportedError("Geometry shader not supported");
   1162 
   1163 	if (((flags & FEATURE_SHADER_FLOAT_64) != 0) && !features.shaderFloat64)
   1164 		throw tcu::NotSupportedError("Double-precision floats not supported");
   1165 
   1166 	if (((flags & FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS) != 0) && !features.vertexPipelineStoresAndAtomics)
   1167 		throw tcu::NotSupportedError("SSBO and image writes not supported in vertex pipeline");
   1168 
   1169 	if (((flags & FEATURE_FRAGMENT_STORES_AND_ATOMICS) != 0) && !features.fragmentStoresAndAtomics)
   1170 		throw tcu::NotSupportedError("SSBO and image writes not supported in fragment shader");
   1171 
   1172 	if (((flags & FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE) != 0) && !features.shaderTessellationAndGeometryPointSize)
   1173 		throw tcu::NotSupportedError("Tessellation and geometry shaders don't support PointSize built-in");
   1174 }
   1175 
   1176 } // tessellation
   1177 } // vkt
   1178