• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef _VKTTESSELLATIONUTIL_HPP
2 #define _VKTTESSELLATIONUTIL_HPP
3 /*------------------------------------------------------------------------
4  * Vulkan Conformance Tests
5  * ------------------------
6  *
7  * Copyright (c) 2014 The Android Open Source Project
8  * Copyright (c) 2016 The Khronos Group Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Tessellation Utilities
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vkDefs.hpp"
28 #include "vkMemUtil.hpp"
29 #include "vkRef.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vktTestCase.hpp"
35 
36 #include "tcuVector.hpp"
37 #include "tcuMaybe.hpp"
38 
39 #include "deStringUtil.hpp"
40 
41 #include <algorithm>  // sort
42 #include <iterator>   // distance
43 
44 namespace vkt
45 {
46 namespace tessellation
47 {
48 
49 class GraphicsPipelineBuilder
50 {
51 public:
GraphicsPipelineBuilder(void)52 								GraphicsPipelineBuilder	(void) : m_renderSize				(0, 0)
53 															   , m_shaderStageFlags			(0u)
54 															   , m_cullModeFlags			(vk::VK_CULL_MODE_NONE)
55 															   , m_frontFace				(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
56 															   , m_patchControlPoints		(1u)
57 															   , m_blendEnable				(false)
58 															   , m_primitiveTopology		(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
59 															   , m_tessellationDomainOrigin	(tcu::Nothing) {}
60 
setRenderSize(const tcu::IVec2 & size)61 	GraphicsPipelineBuilder&	setRenderSize					(const tcu::IVec2& size) { m_renderSize = size; return *this; }
62 	GraphicsPipelineBuilder&	setShader						(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary& binary, const vk::VkSpecializationInfo* specInfo);
setPatchControlPoints(const deUint32 controlPoints)63 	GraphicsPipelineBuilder&	setPatchControlPoints			(const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; }
setCullModeFlags(const vk::VkCullModeFlags cullModeFlags)64 	GraphicsPipelineBuilder&	setCullModeFlags				(const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; }
setFrontFace(const vk::VkFrontFace frontFace)65 	GraphicsPipelineBuilder&	setFrontFace					(const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; }
setBlend(const bool enable)66 	GraphicsPipelineBuilder&	setBlend						(const bool enable) { m_blendEnable = enable; return *this; }
67 
68 	//! Applies only to pipelines without tessellation shaders.
setPrimitiveTopology(const vk::VkPrimitiveTopology topology)69 	GraphicsPipelineBuilder&	setPrimitiveTopology			(const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; }
70 
addVertexBinding(const vk::VkVertexInputBindingDescription vertexBinding)71 	GraphicsPipelineBuilder&	addVertexBinding				(const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; }
addVertexAttribute(const vk::VkVertexInputAttributeDescription vertexAttribute)72 	GraphicsPipelineBuilder&	addVertexAttribute				(const vk::VkVertexInputAttributeDescription vertexAttribute) { m_vertexInputAttributes.push_back(vertexAttribute); return *this; }
73 
74 	//! Basic vertex input configuration (uses biding 0, location 0, etc.)
75 	GraphicsPipelineBuilder&	setVertexInputSingleAttribute	(const vk::VkFormat vertexFormat, const deUint32 stride);
76 
77 	//! If tessellation domain origin is set, pipeline requires VK__maintenance2
setTessellationDomainOrigin(const vk::VkTessellationDomainOrigin domainOrigin)78 	GraphicsPipelineBuilder&	setTessellationDomainOrigin		(const vk::VkTessellationDomainOrigin domainOrigin) { return setTessellationDomainOrigin(tcu::just(domainOrigin)); }
setTessellationDomainOrigin(const tcu::Maybe<vk::VkTessellationDomainOrigin> & domainOrigin)79 	GraphicsPipelineBuilder&	setTessellationDomainOrigin		(const tcu::Maybe<vk::VkTessellationDomainOrigin>& domainOrigin) { m_tessellationDomainOrigin = domainOrigin; return *this; }
80 
81 	vk::Move<vk::VkPipeline>	build							(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass);
82 
83 private:
84 	tcu::IVec2											m_renderSize;
85 	vk::Move<vk::VkShaderModule>						m_vertexShaderModule;
86 	vk::Move<vk::VkShaderModule>						m_fragmentShaderModule;
87 	vk::Move<vk::VkShaderModule>						m_geometryShaderModule;
88 	vk::Move<vk::VkShaderModule>						m_tessControlShaderModule;
89 	vk::Move<vk::VkShaderModule>						m_tessEvaluationShaderModule;
90 	std::vector<vk::VkPipelineShaderStageCreateInfo>	m_shaderStages;
91 	std::vector<vk::VkVertexInputBindingDescription>	m_vertexInputBindings;
92 	std::vector<vk::VkVertexInputAttributeDescription>	m_vertexInputAttributes;
93 	vk::VkShaderStageFlags								m_shaderStageFlags;
94 	vk::VkCullModeFlags									m_cullModeFlags;
95 	vk::VkFrontFace										m_frontFace;
96 	deUint32											m_patchControlPoints;
97 	bool												m_blendEnable;
98 	vk::VkPrimitiveTopology								m_primitiveTopology;
99 	tcu::Maybe<vk::VkTessellationDomainOrigin>			m_tessellationDomainOrigin;
100 
101 	GraphicsPipelineBuilder (const GraphicsPipelineBuilder&); // "deleted"
102 	GraphicsPipelineBuilder& operator= (const GraphicsPipelineBuilder&);
103 };
104 
105 struct TessLevels
106 {
107 	float inner[2];
108 	float outer[4];
109 };
110 
111 enum TessPrimitiveType
112 {
113 	TESSPRIMITIVETYPE_TRIANGLES = 0,
114 	TESSPRIMITIVETYPE_QUADS,
115 	TESSPRIMITIVETYPE_ISOLINES,
116 
117 	TESSPRIMITIVETYPE_LAST,
118 };
119 
120 enum SpacingMode
121 {
122 	SPACINGMODE_EQUAL = 0,
123 	SPACINGMODE_FRACTIONAL_ODD,
124 	SPACINGMODE_FRACTIONAL_EVEN,
125 
126 	SPACINGMODE_LAST,
127 };
128 
129 enum Winding
130 {
131 	WINDING_CCW = 0,
132 	WINDING_CW,
133 
134 	WINDING_LAST,
135 };
136 
137 enum ShaderLanguage
138 {
139 	SHADER_LANGUAGE_GLSL = 0,
140 	SHADER_LANGUAGE_HLSL = 1,
141 
142 	SHADER_LANGUAGE_LAST,
143 };
144 
145 enum FeatureFlagBits
146 {
147 	FEATURE_TESSELLATION_SHADER							= 1u << 0,
148 	FEATURE_GEOMETRY_SHADER								= 1u << 1,
149 	FEATURE_SHADER_FLOAT_64								= 1u << 2,
150 	FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS			= 1u << 3,
151 	FEATURE_FRAGMENT_STORES_AND_ATOMICS					= 1u << 4,
152 	FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE	= 1u << 5,
153 };
154 typedef deUint32 FeatureFlags;
155 
156 vk::VkImageCreateInfo			makeImageCreateInfo							(const tcu::IVec2& size, const vk::VkFormat format, const vk::VkImageUsageFlags usage, const deUint32 numArrayLayers);
157 vk::Move<vk::VkRenderPass>		makeRenderPassWithoutAttachments			(const vk::DeviceInterface& vk, const vk::VkDevice device);
158 vk::VkBufferImageCopy			makeBufferImageCopy							(const vk::VkExtent3D extent, const vk::VkImageSubresourceLayers subresourceLayers);
159 void							beginRenderPassWithRasterizationDisabled	(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer);
160 void							requireFeatures								(const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
161 float							getClampedTessLevel							(const SpacingMode mode, const float tessLevel);
162 int								getRoundedTessLevel							(const SpacingMode mode, const float clampedTessLevel);
163 int								getClampedRoundedTessLevel					(const SpacingMode mode, const float tessLevel);
164 void							getClampedRoundedTriangleTessLevels			(const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
165 void							getClampedRoundedQuadTessLevels				(const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
166 void							getClampedRoundedIsolineTessLevels			(const SpacingMode mode, const float* outerSrc, int* outerDst);
167 int								numOuterTessellationLevels					(const TessPrimitiveType primitiveType);
168 std::string						getTessellationLevelsString					(const TessLevels& tessLevels, const TessPrimitiveType primitiveType);
169 std::string						getTessellationLevelsString					(const float* inner, const float* outer);
170 bool							isPatchDiscarded							(const TessPrimitiveType primitiveType, const float* outerLevels);
171 std::vector<tcu::Vec3>			generateReferenceTriangleTessCoords			(const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2);
172 std::vector<tcu::Vec3>			generateReferenceQuadTessCoords				(const SpacingMode spacingMode, const int inner0, const int inner1, const int outer0, const int outer1, const int outer2, const int outer3);
173 std::vector<tcu::Vec3>			generateReferenceIsolineTessCoords			(const int outer0, const int outer1);
174 int								referenceVertexCount						(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
175 int								referencePrimitiveCount						(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
176 int								numVerticesPerPrimitive						(const TessPrimitiveType primitiveType, const bool usePointMode);
177 
getTessPrimitiveTypeShaderName(const TessPrimitiveType type,bool forSpirv=false)178 static inline const char* getTessPrimitiveTypeShaderName (const TessPrimitiveType type, bool forSpirv = false)
179 {
180 	static std::string primitiveName[][2] =
181 	{
182 		// glsl name	spirv name
183 		{ "triangles", "Triangles"},
184 		{ "quads"	 , "Quads" },
185 		{ "isolines" , "Isolines" }
186 	};
187 
188 	if (type >= TESSPRIMITIVETYPE_LAST)
189 	{
190 		DE_FATAL("Unexpected primitive type.");
191 		return DE_NULL;
192 	}
193 
194 	return primitiveName[type][forSpirv].c_str();
195 }
196 
getDomainName(const TessPrimitiveType type)197 static inline const char* getDomainName (const TessPrimitiveType type)
198 {
199 	switch (type)
200 	{
201 		case TESSPRIMITIVETYPE_TRIANGLES:	return "tri";
202 		case TESSPRIMITIVETYPE_QUADS:		return "quad";
203 		case TESSPRIMITIVETYPE_ISOLINES:	return "isoline";
204 		default:
205 			DE_FATAL("Unexpected primitive type.");
206 			return DE_NULL;
207 	}
208 }
209 
getOutputTopologyName(const TessPrimitiveType type,const Winding winding,const bool usePointMode)210 static inline const char* getOutputTopologyName (const TessPrimitiveType type, const Winding winding, const bool usePointMode)
211 {
212 	if (usePointMode)
213 		return "point";
214 	else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
215 		return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
216 	else if (type == TESSPRIMITIVETYPE_ISOLINES)
217 		return "line";
218 
219 	DE_FATAL("Unexpected primitive type.");
220 	return DE_NULL;
221 }
222 
getSpacingModeShaderName(SpacingMode mode,bool forSpirv=false)223 static inline const char* getSpacingModeShaderName (SpacingMode mode, bool forSpirv = false)
224 {
225 	static std::string spacingName[][2] =
226 	{
227 		// glsl name					spirv name
228 		{ "equal_spacing",				"SpacingEqual"},
229 		{ "fractional_odd_spacing",		"SpacingFractionalOdd" },
230 		{ "fractional_even_spacing",	"SpacingFractionalEven" }
231 	};
232 
233 	if (mode >= SPACINGMODE_LAST)
234 	{
235 		DE_FATAL("Unexpected spacing type.");
236 		return DE_NULL;
237 	}
238 
239 	return spacingName[mode][forSpirv].c_str();
240 }
241 
getPartitioningShaderName(SpacingMode mode)242 static inline const char* getPartitioningShaderName (SpacingMode mode)
243 {
244 	switch (mode)
245 	{
246 		case SPACINGMODE_EQUAL:				return "integer";
247 		case SPACINGMODE_FRACTIONAL_ODD:	return "fractional_odd";
248 		case SPACINGMODE_FRACTIONAL_EVEN:	return "fractional_even";
249 		default:
250 			DE_FATAL("Unexpected spacing mode.");
251 			return DE_NULL;
252 	}
253 }
254 
getWindingShaderName(const Winding winding)255 static inline const char* getWindingShaderName (const Winding winding)
256 {
257 	switch (winding)
258 	{
259 		case WINDING_CCW:	return "ccw";
260 		case WINDING_CW:	return "cw";
261 		default:
262 			DE_FATAL("Unexpected winding type.");
263 			return DE_NULL;
264 	}
265 }
266 
getShaderLanguageName(const ShaderLanguage language)267 static inline const char* getShaderLanguageName (const ShaderLanguage language)
268 {
269 	switch (language)
270 	{
271 		case SHADER_LANGUAGE_GLSL:	return "glsl";
272 		case SHADER_LANGUAGE_HLSL:	return "hlsl";
273 		default:
274 			DE_FATAL("Unexpected shader language.");
275 			return DE_NULL;
276 	}
277 }
278 
getGeometryShaderInputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)279 static inline const char* getGeometryShaderInputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
280 {
281 	if (usePointMode)
282 		return "points";
283 
284 	switch (type)
285 	{
286 		case TESSPRIMITIVETYPE_TRIANGLES:
287 		case TESSPRIMITIVETYPE_QUADS:
288 			return "triangles";
289 
290 		case TESSPRIMITIVETYPE_ISOLINES:
291 			return "lines";
292 
293 		default:
294 			DE_FATAL("Unexpected primitive type.");
295 			return DE_NULL;
296 	}
297 }
298 
getGeometryShaderOutputPrimitiveTypeShaderName(const TessPrimitiveType type,const bool usePointMode)299 static inline const char* getGeometryShaderOutputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
300 {
301 	if (usePointMode)
302 		return "points";
303 
304 	switch (type)
305 	{
306 		case TESSPRIMITIVETYPE_TRIANGLES:
307 		case TESSPRIMITIVETYPE_QUADS:
308 			return "triangle_strip";
309 
310 		case TESSPRIMITIVETYPE_ISOLINES:
311 			return "line_strip";
312 
313 		default:
314 			DE_FATAL("Unexpected primitive type.");
315 			return DE_NULL;
316 	}
317 }
318 
319 #ifndef CTS_USES_VULKANSC
320 
getPortability(const Context & context)321 static inline const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* getPortability (const Context& context)
322 {
323 	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
324 		return &context.getPortabilitySubsetFeatures();
325 	return DE_NULL;
326 }
327 
checkIsolines(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)328 static inline void checkIsolines (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features)
329 {
330 	if (!features.tessellationIsolines)
331 		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Tessellation iso lines are not supported by this implementation");
332 }
333 
checkPrimitive(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features,const TessPrimitiveType primitive)334 static inline void checkPrimitive (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features, const TessPrimitiveType primitive)
335 {
336 	if (primitive == TESSPRIMITIVETYPE_ISOLINES)
337 		checkIsolines(features);
338 }
339 
checkSupportPrimitive(Context & context,const TessPrimitiveType primitive)340 static inline void checkSupportPrimitive (Context& context, const TessPrimitiveType primitive)
341 {
342 	if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
343 		checkPrimitive(*features, primitive);
344 }
345 
checkPointMode(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR & features)346 static inline void checkPointMode (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features)
347 {
348 	if (!features.tessellationPointMode)
349 		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Tessellation point mode is not supported by this implementation");
350 }
351 
352 #endif // CTS_USES_VULKANSC
353 
354 template<typename T>
sizeInBytes(const std::vector<T> & vec)355 inline std::size_t sizeInBytes (const std::vector<T>& vec)
356 {
357 	return vec.size() * sizeof(vec[0]);
358 }
359 
360 template <typename T>
sorted(const std::vector<T> & unsorted)361 static std::vector<T> sorted (const std::vector<T>& unsorted)
362 {
363 	std::vector<T> result = unsorted;
364 	std::sort(result.begin(), result.end());
365 	return result;
366 }
367 
368 template <typename T, typename P>
sorted(const std::vector<T> & unsorted,P pred)369 static std::vector<T> sorted (const std::vector<T>& unsorted, P pred)
370 {
371 	std::vector<T> result = unsorted;
372 	std::sort(result.begin(), result.end(), pred);
373 	return result;
374 }
375 
376 template <typename IterT>
elemsStr(const IterT & begin,const IterT & end,int wrapLengthParam=0,int numIndentationSpaces=0)377 std::string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
378 {
379 	const int			bigInt			= ~0u/2;
380 	const std::string	baseIndentation	= std::string(numIndentationSpaces, ' ');
381 	const std::string	deepIndentation	= baseIndentation + std::string(4, ' ');
382 	const int			wrapLength		= wrapLengthParam > 0 ? wrapLengthParam : bigInt;
383 	const int			length			= static_cast<int>(std::distance(begin, end));
384 	std::string			result;
385 
386 	if (length > wrapLength)
387 		result += "(amount: " + de::toString(length) + ") ";
388 	result += std::string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
389 
390 	{
391 		int index = 0;
392 		for (IterT it = begin; it != end; ++it)
393 		{
394 			if (it != begin)
395 				result += std::string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
396 			result += de::toString(*it);
397 			index++;
398 		}
399 
400 		result += length > wrapLength ? "\n"+baseIndentation : " ";
401 	}
402 
403 	result += "}";
404 	return result;
405 }
406 
407 template <typename ContainerT>
containerStr(const ContainerT & c,int wrapLengthParam=0,int numIndentationSpaces=0)408 std::string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
409 {
410 	return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
411 }
412 
413 //! Copy 'count' objects of type T from 'memory' into a vector.
414 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
415 template<typename T>
readInterleavedData(const int count,const void * memory,const int offset,const int stride)416 std::vector<T> readInterleavedData (const int count, const void* memory, const int offset, const int stride)
417 {
418 	std::vector<T> results(count);
419 	const deUint8* pData = static_cast<const deUint8*>(memory) + offset;
420 
421 	for (int i = 0; i < count; ++i)
422 	{
423 		deMemcpy(&results[i], pData, sizeof(T));
424 		pData += stride;
425 	}
426 
427 	return results;
428 }
429 
430 template <typename CaseDef, typename = bool>
431 struct PointMode
432 {
433 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode434 	static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR&, const CaseDef)
435 	{
436 	}
437 #endif // CTS_USES_VULKANSC
438 };
439 
440 template <typename CaseDef>
441 struct PointMode<CaseDef, decltype(CaseDef().usePointMode)>
442 {
443 #ifndef CTS_USES_VULKANSC
checkvkt::tessellation::PointMode444 	static void check(const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR& features, const CaseDef caseDef)
445 	{
446 		if (caseDef.usePointMode)
447 			checkPointMode(features);
448 	}
449 #endif // CTS_USES_VULKANSC
450 };
451 
452 template <typename CaseDef>
checkSupportCase(Context & context,const CaseDef caseDef)453 void checkSupportCase (Context& context, const CaseDef caseDef)
454 {
455 #ifndef CTS_USES_VULKANSC
456 	if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
457 	{
458 		PointMode<CaseDef>::check(*features, caseDef);
459 		checkPrimitive(*features, caseDef.primitiveType);
460 }
461 #else
462 	DE_UNREF(context);
463 	DE_UNREF(caseDef);
464 #endif // CTS_USES_VULKANSC
465 }
466 
467 } // tessellation
468 } // vkt
469 
470 #endif // _VKTTESSELLATIONUTIL_HPP
471