Home | History | Annotate | Download | only in tessellation
      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 
     34 #include "tcuVector.hpp"
     35 #include "tcuMaybe.hpp"
     36 
     37 #include "deStringUtil.hpp"
     38 
     39 #include <algorithm>  // sort
     40 #include <iterator>   // distance
     41 
     42 namespace vkt
     43 {
     44 namespace tessellation
     45 {
     46 
     47 class Buffer
     48 {
     49 public:
     50 										Buffer			(const vk::DeviceInterface&		vk,
     51 														 const vk::VkDevice				device,
     52 														 vk::Allocator&					allocator,
     53 														 const vk::VkBufferCreateInfo&	bufferCreateInfo,
     54 														 const vk::MemoryRequirement	memoryRequirement)
     55 
     56 											: m_buffer		(createBuffer(vk, device, &bufferCreateInfo))
     57 											, m_allocation	(allocator.allocate(getBufferMemoryRequirements(vk, device, *m_buffer), memoryRequirement))
     58 										{
     59 											VK_CHECK(vk.bindBufferMemory(device, *m_buffer, m_allocation->getMemory(), m_allocation->getOffset()));
     60 										}
     61 
     62 	const vk::VkBuffer&					get				(void) const { return *m_buffer; }
     63 	const vk::VkBuffer&					operator*		(void) const { return get(); }
     64 	vk::Allocation&						getAllocation	(void) const { return *m_allocation; }
     65 
     66 private:
     67 	const vk::Unique<vk::VkBuffer>		m_buffer;
     68 	const de::UniquePtr<vk::Allocation>	m_allocation;
     69 
     70 	// "deleted"
     71 										Buffer			(const Buffer&);
     72 	Buffer&								operator=		(const Buffer&);
     73 };
     74 
     75 class Image
     76 {
     77 public:
     78 										Image			(const vk::DeviceInterface&		vk,
     79 														 const vk::VkDevice				device,
     80 														 vk::Allocator&					allocator,
     81 														 const vk::VkImageCreateInfo&	imageCreateInfo,
     82 														 const vk::MemoryRequirement	memoryRequirement)
     83 
     84 											: m_image		(createImage(vk, device, &imageCreateInfo))
     85 											, m_allocation	(allocator.allocate(getImageMemoryRequirements(vk, device, *m_image), memoryRequirement))
     86 										{
     87 											VK_CHECK(vk.bindImageMemory(device, *m_image, m_allocation->getMemory(), m_allocation->getOffset()));
     88 										}
     89 
     90 	const vk::VkImage&					get				(void) const { return *m_image; }
     91 	const vk::VkImage&					operator*		(void) const { return get(); }
     92 	vk::Allocation&						getAllocation	(void) const { return *m_allocation; }
     93 
     94 private:
     95 	const vk::Unique<vk::VkImage>		m_image;
     96 	const de::UniquePtr<vk::Allocation>	m_allocation;
     97 
     98 	// "deleted"
     99 										Image			(const Image&);
    100 	Image&								operator=		(const Image&);
    101 };
    102 
    103 class GraphicsPipelineBuilder
    104 {
    105 public:
    106 								GraphicsPipelineBuilder	(void) : m_renderSize				(0, 0)
    107 															   , m_shaderStageFlags			(0u)
    108 															   , m_cullModeFlags			(vk::VK_CULL_MODE_NONE)
    109 															   , m_frontFace				(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
    110 															   , m_patchControlPoints		(1u)
    111 															   , m_blendEnable				(false)
    112 															   , m_primitiveTopology		(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
    113 															   , m_tessellationDomainOrigin	(tcu::nothing<vk::VkTessellationDomainOrigin>()) {}
    114 
    115 	GraphicsPipelineBuilder&	setRenderSize					(const tcu::IVec2& size) { m_renderSize = size; return *this; }
    116 	GraphicsPipelineBuilder&	setShader						(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkShaderStageFlagBits stage, const vk::ProgramBinary& binary, const vk::VkSpecializationInfo* specInfo);
    117 	GraphicsPipelineBuilder&	setPatchControlPoints			(const deUint32 controlPoints) { m_patchControlPoints = controlPoints; return *this; }
    118 	GraphicsPipelineBuilder&	setCullModeFlags				(const vk::VkCullModeFlags cullModeFlags) { m_cullModeFlags = cullModeFlags; return *this; }
    119 	GraphicsPipelineBuilder&	setFrontFace					(const vk::VkFrontFace frontFace) { m_frontFace = frontFace; return *this; }
    120 	GraphicsPipelineBuilder&	setBlend						(const bool enable) { m_blendEnable = enable; return *this; }
    121 
    122 	//! Applies only to pipelines without tessellation shaders.
    123 	GraphicsPipelineBuilder&	setPrimitiveTopology			(const vk::VkPrimitiveTopology topology) { m_primitiveTopology = topology; return *this; }
    124 
    125 	GraphicsPipelineBuilder&	addVertexBinding				(const vk::VkVertexInputBindingDescription vertexBinding) { m_vertexInputBindings.push_back(vertexBinding); return *this; }
    126 	GraphicsPipelineBuilder&	addVertexAttribute				(const vk::VkVertexInputAttributeDescription vertexAttribute) { m_vertexInputAttributes.push_back(vertexAttribute); return *this; }
    127 
    128 	//! Basic vertex input configuration (uses biding 0, location 0, etc.)
    129 	GraphicsPipelineBuilder&	setVertexInputSingleAttribute	(const vk::VkFormat vertexFormat, const deUint32 stride);
    130 
    131 	//! If tessellation domain origin is set, pipeline requires VK__maintenance2
    132 	GraphicsPipelineBuilder&	setTessellationDomainOrigin		(const vk::VkTessellationDomainOrigin domainOrigin) { return setTessellationDomainOrigin(tcu::just(domainOrigin)); }
    133 	GraphicsPipelineBuilder&	setTessellationDomainOrigin		(const tcu::Maybe<vk::VkTessellationDomainOrigin>& domainOrigin) { m_tessellationDomainOrigin = domainOrigin; return *this; }
    134 
    135 	vk::Move<vk::VkPipeline>	build							(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkRenderPass renderPass);
    136 
    137 private:
    138 	tcu::IVec2											m_renderSize;
    139 	vk::Move<vk::VkShaderModule>						m_vertexShaderModule;
    140 	vk::Move<vk::VkShaderModule>						m_fragmentShaderModule;
    141 	vk::Move<vk::VkShaderModule>						m_geometryShaderModule;
    142 	vk::Move<vk::VkShaderModule>						m_tessControlShaderModule;
    143 	vk::Move<vk::VkShaderModule>						m_tessEvaluationShaderModule;
    144 	std::vector<vk::VkPipelineShaderStageCreateInfo>	m_shaderStages;
    145 	std::vector<vk::VkVertexInputBindingDescription>	m_vertexInputBindings;
    146 	std::vector<vk::VkVertexInputAttributeDescription>	m_vertexInputAttributes;
    147 	vk::VkShaderStageFlags								m_shaderStageFlags;
    148 	vk::VkCullModeFlags									m_cullModeFlags;
    149 	vk::VkFrontFace										m_frontFace;
    150 	deUint32											m_patchControlPoints;
    151 	bool												m_blendEnable;
    152 	vk::VkPrimitiveTopology								m_primitiveTopology;
    153 	tcu::Maybe<vk::VkTessellationDomainOrigin>			m_tessellationDomainOrigin;
    154 
    155 	GraphicsPipelineBuilder (const GraphicsPipelineBuilder&); // "deleted"
    156 	GraphicsPipelineBuilder& operator= (const GraphicsPipelineBuilder&);
    157 };
    158 
    159 struct TessLevels
    160 {
    161 	float inner[2];
    162 	float outer[4];
    163 };
    164 
    165 enum TessPrimitiveType
    166 {
    167 	TESSPRIMITIVETYPE_TRIANGLES = 0,
    168 	TESSPRIMITIVETYPE_QUADS,
    169 	TESSPRIMITIVETYPE_ISOLINES,
    170 
    171 	TESSPRIMITIVETYPE_LAST,
    172 };
    173 
    174 enum SpacingMode
    175 {
    176 	SPACINGMODE_EQUAL = 0,
    177 	SPACINGMODE_FRACTIONAL_ODD,
    178 	SPACINGMODE_FRACTIONAL_EVEN,
    179 
    180 	SPACINGMODE_LAST,
    181 };
    182 
    183 enum Winding
    184 {
    185 	WINDING_CCW = 0,
    186 	WINDING_CW,
    187 
    188 	WINDING_LAST,
    189 };
    190 
    191 enum ShaderLanguage
    192 {
    193 	SHADER_LANGUAGE_GLSL = 0,
    194 	SHADER_LANGUAGE_HLSL = 1,
    195 
    196 	SHADER_LANGUAGE_LAST,
    197 };
    198 
    199 enum FeatureFlagBits
    200 {
    201 	FEATURE_TESSELLATION_SHADER							= 1u << 0,
    202 	FEATURE_GEOMETRY_SHADER								= 1u << 1,
    203 	FEATURE_SHADER_FLOAT_64								= 1u << 2,
    204 	FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS			= 1u << 3,
    205 	FEATURE_FRAGMENT_STORES_AND_ATOMICS					= 1u << 4,
    206 	FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE	= 1u << 5,
    207 };
    208 typedef deUint32 FeatureFlags;
    209 
    210 vk::VkBufferCreateInfo			makeBufferCreateInfo						(const vk::VkDeviceSize bufferSize, const vk::VkBufferUsageFlags usage);
    211 vk::VkImageCreateInfo			makeImageCreateInfo							(const tcu::IVec2& size, const vk::VkFormat format, const vk::VkImageUsageFlags usage, const deUint32 numArrayLayers);
    212 vk::Move<vk::VkCommandPool>		makeCommandPool								(const vk::DeviceInterface& vk, const vk::VkDevice device, const deUint32 queueFamilyIndex);
    213 vk::Move<vk::VkDescriptorSet>	makeDescriptorSet							(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkDescriptorPool descriptorPool, const vk::VkDescriptorSetLayout setLayout);
    214 vk::Move<vk::VkPipelineLayout>	makePipelineLayout							(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkDescriptorSetLayout descriptorSetLayout);
    215 vk::Move<vk::VkPipelineLayout>	makePipelineLayoutWithoutDescriptors		(const vk::DeviceInterface& vk, const vk::VkDevice device);
    216 vk::Move<vk::VkPipeline>		makeComputePipeline							(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkPipelineLayout pipelineLayout, const vk::VkShaderModule shaderModule, const vk::VkSpecializationInfo* specInfo);
    217 vk::Move<vk::VkRenderPass>		makeRenderPass								(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkFormat colorFormat);
    218 vk::Move<vk::VkRenderPass>		makeRenderPassWithoutAttachments			(const vk::DeviceInterface& vk, const vk::VkDevice device);
    219 vk::Move<vk::VkFramebuffer>		makeFramebuffer								(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkRenderPass renderPass, const vk::VkImageView colorAttachment, const deUint32 width, const deUint32 height, const deUint32 layers);
    220 vk::Move<vk::VkFramebuffer>		makeFramebufferWithoutAttachments			(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkRenderPass renderPass);
    221 vk::Move<vk::VkImageView>		makeImageView								(const vk::DeviceInterface& vk, const vk::VkDevice vkDevice, const vk::VkImage image, const vk::VkImageViewType viewType, const vk::VkFormat format, const vk::VkImageSubresourceRange subresourceRange);
    222 vk::VkBufferImageCopy			makeBufferImageCopy							(const vk::VkExtent3D extent, const vk::VkImageSubresourceLayers subresourceLayers);
    223 vk::VkBufferMemoryBarrier		makeBufferMemoryBarrier						(const vk::VkAccessFlags srcAccessMask, const vk::VkAccessFlags dstAccessMask, const vk::VkBuffer buffer, const vk::VkDeviceSize offset, const vk::VkDeviceSize bufferSizeBytes);
    224 vk::VkImageMemoryBarrier		makeImageMemoryBarrier						(const vk::VkAccessFlags srcAccessMask, const vk::VkAccessFlags dstAccessMask, const vk::VkImageLayout oldLayout, const vk::VkImageLayout newLayout, const vk::VkImage image, const vk::VkImageSubresourceRange subresourceRange);
    225 
    226 void							beginCommandBuffer							(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer);
    227 void							endCommandBuffer							(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer);
    228 void							submitCommandsAndWait						(const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkQueue queue, const vk::VkCommandBuffer commandBuffer);
    229 void							beginRenderPass								(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer, const vk::VkRect2D& renderArea, const tcu::Vec4& clearColor);
    230 void							beginRenderPassWithRasterizationDisabled	(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer, const vk::VkRenderPass renderPass, const vk::VkFramebuffer framebuffer);
    231 void							endRenderPass								(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer);
    232 void							requireFeatures								(const vk::InstanceInterface& vki, const vk::VkPhysicalDevice physDevice, const FeatureFlags flags);
    233 
    234 float							getClampedTessLevel							(const SpacingMode mode, const float tessLevel);
    235 int								getRoundedTessLevel							(const SpacingMode mode, const float clampedTessLevel);
    236 int								getClampedRoundedTessLevel					(const SpacingMode mode, const float tessLevel);
    237 void							getClampedRoundedTriangleTessLevels			(const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
    238 void							getClampedRoundedQuadTessLevels				(const SpacingMode mode, const float* innerSrc, const float* outerSrc, int* innerDst, int* outerDst);
    239 void							getClampedRoundedIsolineTessLevels			(const SpacingMode mode, const float* outerSrc, int* outerDst);
    240 int								numOuterTessellationLevels					(const TessPrimitiveType primitiveType);
    241 std::string						getTessellationLevelsString					(const TessLevels& tessLevels, const TessPrimitiveType primitiveType);
    242 std::string						getTessellationLevelsString					(const float* inner, const float* outer);
    243 bool							isPatchDiscarded							(const TessPrimitiveType primitiveType, const float* outerLevels);
    244 std::vector<tcu::Vec3>			generateReferenceTriangleTessCoords			(const SpacingMode spacingMode, const int inner, const int outer0, const int outer1, const int outer2);
    245 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);
    246 std::vector<tcu::Vec3>			generateReferenceIsolineTessCoords			(const int outer0, const int outer1);
    247 int								referenceVertexCount						(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
    248 int								referencePrimitiveCount						(const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const bool usePointMode, const float* innerLevels, const float* outerLevels);
    249 int								numVerticesPerPrimitive						(const TessPrimitiveType primitiveType, const bool usePointMode);
    250 
    251 static inline const char* getTessPrimitiveTypeShaderName (const TessPrimitiveType type)
    252 {
    253 	switch (type)
    254 	{
    255 		case TESSPRIMITIVETYPE_TRIANGLES:	return "triangles";
    256 		case TESSPRIMITIVETYPE_QUADS:		return "quads";
    257 		case TESSPRIMITIVETYPE_ISOLINES:	return "isolines";
    258 		default:
    259 			DE_FATAL("Unexpected primitive type.");
    260 			return DE_NULL;
    261 	}
    262 }
    263 
    264 static inline const char* getDomainName (const TessPrimitiveType type)
    265 {
    266 	switch (type)
    267 	{
    268 		case TESSPRIMITIVETYPE_TRIANGLES:	return "tri";
    269 		case TESSPRIMITIVETYPE_QUADS:		return "quad";
    270 		case TESSPRIMITIVETYPE_ISOLINES:	return "isoline";
    271 		default:
    272 			DE_FATAL("Unexpected primitive type.");
    273 			return DE_NULL;
    274 	}
    275 }
    276 
    277 static inline const char* getOutputTopologyName (const TessPrimitiveType type, const Winding winding, const bool usePointMode)
    278 {
    279 	if (usePointMode)
    280 		return "point";
    281 	else if (type == TESSPRIMITIVETYPE_TRIANGLES || type == TESSPRIMITIVETYPE_QUADS)
    282 		return (winding == WINDING_CCW ? "triangle_ccw" : "triangle_cw");
    283 	else if (type == TESSPRIMITIVETYPE_ISOLINES)
    284 		return "line";
    285 
    286 	DE_FATAL("Unexpected primitive type.");
    287 	return DE_NULL;
    288 }
    289 
    290 static inline const char* getSpacingModeShaderName (SpacingMode mode)
    291 {
    292 	switch (mode)
    293 	{
    294 		case SPACINGMODE_EQUAL:				return "equal_spacing";
    295 		case SPACINGMODE_FRACTIONAL_ODD:	return "fractional_odd_spacing";
    296 		case SPACINGMODE_FRACTIONAL_EVEN:	return "fractional_even_spacing";
    297 		default:
    298 			DE_FATAL("Unexpected spacing mode.");
    299 			return DE_NULL;
    300 	}
    301 }
    302 
    303 static inline const char* getPartitioningShaderName (SpacingMode mode)
    304 {
    305 	switch (mode)
    306 	{
    307 		case SPACINGMODE_EQUAL:				return "integer";
    308 		case SPACINGMODE_FRACTIONAL_ODD:	return "fractional_odd";
    309 		case SPACINGMODE_FRACTIONAL_EVEN:	return "fractional_even";
    310 		default:
    311 			DE_FATAL("Unexpected spacing mode.");
    312 			return DE_NULL;
    313 	}
    314 }
    315 
    316 static inline const char* getWindingShaderName (const Winding winding)
    317 {
    318 	switch (winding)
    319 	{
    320 		case WINDING_CCW:	return "ccw";
    321 		case WINDING_CW:	return "cw";
    322 		default:
    323 			DE_FATAL("Unexpected winding type.");
    324 			return DE_NULL;
    325 	}
    326 }
    327 
    328 static inline const char* getShaderLanguageName (const ShaderLanguage language)
    329 {
    330 	switch (language)
    331 	{
    332 		case SHADER_LANGUAGE_GLSL:	return "glsl";
    333 		case SHADER_LANGUAGE_HLSL:	return "hlsl";
    334 		default:
    335 			DE_FATAL("Unexpected shader language.");
    336 			return DE_NULL;
    337 	}
    338 }
    339 
    340 static inline const char* getGeometryShaderInputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
    341 {
    342 	if (usePointMode)
    343 		return "points";
    344 
    345 	switch (type)
    346 	{
    347 		case TESSPRIMITIVETYPE_TRIANGLES:
    348 		case TESSPRIMITIVETYPE_QUADS:
    349 			return "triangles";
    350 
    351 		case TESSPRIMITIVETYPE_ISOLINES:
    352 			return "lines";
    353 
    354 		default:
    355 			DE_FATAL("Unexpected primitive type.");
    356 			return DE_NULL;
    357 	}
    358 }
    359 
    360 static inline const char* getGeometryShaderOutputPrimitiveTypeShaderName (const TessPrimitiveType type, const bool usePointMode)
    361 {
    362 	if (usePointMode)
    363 		return "points";
    364 
    365 	switch (type)
    366 	{
    367 		case TESSPRIMITIVETYPE_TRIANGLES:
    368 		case TESSPRIMITIVETYPE_QUADS:
    369 			return "triangle_strip";
    370 
    371 		case TESSPRIMITIVETYPE_ISOLINES:
    372 			return "line_strip";
    373 
    374 		default:
    375 			DE_FATAL("Unexpected primitive type.");
    376 			return DE_NULL;
    377 	}
    378 }
    379 
    380 template<typename T>
    381 inline std::size_t sizeInBytes (const std::vector<T>& vec)
    382 {
    383 	return vec.size() * sizeof(vec[0]);
    384 }
    385 
    386 template <typename T>
    387 static std::vector<T> sorted (const std::vector<T>& unsorted)
    388 {
    389 	std::vector<T> result = unsorted;
    390 	std::sort(result.begin(), result.end());
    391 	return result;
    392 }
    393 
    394 template <typename T, typename P>
    395 static std::vector<T> sorted (const std::vector<T>& unsorted, P pred)
    396 {
    397 	std::vector<T> result = unsorted;
    398 	std::sort(result.begin(), result.end(), pred);
    399 	return result;
    400 }
    401 
    402 template <typename IterT>
    403 std::string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
    404 {
    405 	const int			bigInt			= ~0u/2;
    406 	const std::string	baseIndentation	= std::string(numIndentationSpaces, ' ');
    407 	const std::string	deepIndentation	= baseIndentation + std::string(4, ' ');
    408 	const int			wrapLength		= wrapLengthParam > 0 ? wrapLengthParam : bigInt;
    409 	const int			length			= static_cast<int>(std::distance(begin, end));
    410 	std::string			result;
    411 
    412 	if (length > wrapLength)
    413 		result += "(amount: " + de::toString(length) + ") ";
    414 	result += std::string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
    415 
    416 	{
    417 		int index = 0;
    418 		for (IterT it = begin; it != end; ++it)
    419 		{
    420 			if (it != begin)
    421 				result += std::string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
    422 			result += de::toString(*it);
    423 			index++;
    424 		}
    425 
    426 		result += length > wrapLength ? "\n"+baseIndentation : " ";
    427 	}
    428 
    429 	result += "}";
    430 	return result;
    431 }
    432 
    433 template <typename ContainerT>
    434 std::string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
    435 {
    436 	return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
    437 }
    438 
    439 //! Copy 'count' objects of type T from 'memory' into a vector.
    440 //! 'offset' is the offset of first object in memory, and 'stride' is the distance between consecutive objects.
    441 template<typename T>
    442 std::vector<T> readInterleavedData (const int count, const void* memory, const int offset, const int stride)
    443 {
    444 	std::vector<T> results(count);
    445 	const deUint8* pData = static_cast<const deUint8*>(memory) + offset;
    446 
    447 	for (int i = 0; i < count; ++i)
    448 	{
    449 		deMemcpy(&results[i], pData, sizeof(T));
    450 		pData += stride;
    451 	}
    452 
    453 	return results;
    454 }
    455 
    456 } // tessellation
    457 } // vkt
    458 
    459 #endif // _VKTTESSELLATIONUTIL_HPP
    460