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