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