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