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