Home | History | Annotate | Download | only in vulkan
      1 /*-------------------------------------------------------------------------
      2  * Vulkan CTS Framework
      3  * --------------------
      4  *
      5  * Copyright (c) 2015 Google Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Memory management utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vkMemUtil.hpp"
     25 #include "vkStrUtil.hpp"
     26 #include "vkQueryUtil.hpp"
     27 #include "vkRef.hpp"
     28 #include "vkRefUtil.hpp"
     29 #include "deInt32.h"
     30 
     31 #include <sstream>
     32 
     33 namespace vk
     34 {
     35 
     36 using de::UniquePtr;
     37 using de::MovePtr;
     38 
     39 namespace
     40 {
     41 
     42 class HostPtr
     43 {
     44 public:
     45 								HostPtr		(const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags);
     46 								~HostPtr	(void);
     47 
     48 	void*						get			(void) const { return m_ptr; }
     49 
     50 private:
     51 	const DeviceInterface&		m_vkd;
     52 	const VkDevice				m_device;
     53 	const VkDeviceMemory		m_memory;
     54 	void* const					m_ptr;
     55 };
     56 
     57 HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
     58 	: m_vkd		(vkd)
     59 	, m_device	(device)
     60 	, m_memory	(memory)
     61 	, m_ptr		(mapMemory(vkd, device, memory, offset, size, flags))
     62 {
     63 }
     64 
     65 HostPtr::~HostPtr (void)
     66 {
     67 	m_vkd.unmapMemory(m_device, m_memory);
     68 }
     69 
     70 deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
     71 {
     72 	const deUint32	compatibleTypes	= getCompatibleMemoryTypes(deviceMemProps, requirement);
     73 	const deUint32	candidates		= allowedMemTypeBits & compatibleTypes;
     74 
     75 	if (candidates == 0)
     76 		TCU_THROW(NotSupportedError, "No compatible memory type found");
     77 
     78 	return (deUint32)deCtz32(candidates);
     79 }
     80 
     81 bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
     82 {
     83 	DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
     84 	return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
     85 }
     86 
     87 } // anonymous
     88 
     89 // Allocation
     90 
     91 Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
     92 	: m_memory	(memory)
     93 	, m_offset	(offset)
     94 	, m_hostPtr	(hostPtr)
     95 {
     96 }
     97 
     98 Allocation::~Allocation (void)
     99 {
    100 }
    101 
    102 void flushAlloc (const DeviceInterface& vkd, VkDevice device, const Allocation& alloc)
    103 {
    104 	flushMappedMemoryRange(vkd, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
    105 }
    106 
    107 void invalidateAlloc (const DeviceInterface& vkd, VkDevice device, const Allocation& alloc)
    108 {
    109 	invalidateMappedMemoryRange(vkd, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE);
    110 }
    111 
    112 // MemoryRequirement
    113 
    114 const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
    115 const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
    116 const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
    117 const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
    118 const MemoryRequirement MemoryRequirement::Protected		= MemoryRequirement(MemoryRequirement::FLAG_PROTECTED);
    119 const MemoryRequirement MemoryRequirement::Local			= MemoryRequirement(MemoryRequirement::FLAG_LOCAL);
    120 const MemoryRequirement MemoryRequirement::Cached			= MemoryRequirement(MemoryRequirement::FLAG_CACHED);
    121 const MemoryRequirement MemoryRequirement::NonLocal			= MemoryRequirement(MemoryRequirement::FLAG_NON_LOCAL);
    122 
    123 bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
    124 {
    125 	// sanity check
    126 	if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
    127 		DE_FATAL("Coherent memory must be host-visible");
    128 	if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
    129 		DE_FATAL("Lazily allocated memory cannot be mappable");
    130 	if ((m_flags & FLAG_PROTECTED) && (m_flags & FLAG_HOST_VISIBLE))
    131 		DE_FATAL("Protected memory cannot be mappable");
    132 
    133 	// host-visible
    134 	if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
    135 		return false;
    136 
    137 	// coherent
    138 	if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
    139 		return false;
    140 
    141 	// lazy
    142 	if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
    143 		return false;
    144 
    145 	// protected
    146 	if ((m_flags & FLAG_PROTECTED) && !(heapFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT))
    147 		return false;
    148 
    149 	// local
    150 	if ((m_flags & FLAG_LOCAL) && !(heapFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
    151 		return false;
    152 
    153 	// cached
    154 	if ((m_flags & FLAG_CACHED) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT))
    155 		return false;
    156 
    157 	// non-local
    158 	if ((m_flags & FLAG_NON_LOCAL) && (heapFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
    159 		return false;
    160 
    161 	return true;
    162 }
    163 
    164 MemoryRequirement::MemoryRequirement (deUint32 flags)
    165 	: m_flags(flags)
    166 {
    167 }
    168 
    169 // SimpleAllocator
    170 
    171 class SimpleAllocation : public Allocation
    172 {
    173 public:
    174 									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
    175 	virtual							~SimpleAllocation	(void);
    176 
    177 private:
    178 	const Unique<VkDeviceMemory>	m_memHolder;
    179 	const UniquePtr<HostPtr>		m_hostPtr;
    180 };
    181 
    182 SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
    183 	: Allocation	(*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
    184 	, m_memHolder	(mem)
    185 	, m_hostPtr		(hostPtr)
    186 {
    187 }
    188 
    189 SimpleAllocation::~SimpleAllocation (void)
    190 {
    191 }
    192 
    193 SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
    194 	: m_vk		(vk)
    195 	, m_device	(device)
    196 	, m_memProps(deviceMemProps)
    197 {
    198 }
    199 
    200 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment)
    201 {
    202 	DE_UNREF(alignment);
    203 
    204 	Move<VkDeviceMemory>	mem		= allocateMemory(m_vk, m_device, &allocInfo);
    205 	MovePtr<HostPtr>		hostPtr;
    206 
    207 	if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
    208 		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
    209 
    210 	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
    211 }
    212 
    213 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
    214 {
    215 	const deUint32				memoryTypeNdx	= selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
    216 	const VkMemoryAllocateInfo	allocInfo		=
    217 	{
    218 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType			sType;
    219 		DE_NULL,								//	const void*				pNext;
    220 		memReqs.size,							//	VkDeviceSize			allocationSize;
    221 		memoryTypeNdx,							//	deUint32				memoryTypeIndex;
    222 	};
    223 
    224 	Move<VkDeviceMemory>		mem				= allocateMemory(m_vk, m_device, &allocInfo);
    225 	MovePtr<HostPtr>			hostPtr;
    226 
    227 	if (requirement & MemoryRequirement::HostVisible)
    228 	{
    229 		DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
    230 		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
    231 	}
    232 
    233 	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
    234 }
    235 
    236 static MovePtr<Allocation> allocateDedicated (const InstanceInterface&		vki,
    237 											  const DeviceInterface&		vkd,
    238 											  const VkPhysicalDevice&		physDevice,
    239 											  const VkDevice				device,
    240 											  const VkMemoryRequirements&	memReqs,
    241 											  const MemoryRequirement		requirement,
    242 											  const void*					pNext)
    243 {
    244 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, physDevice);
    245 	const deUint32							memoryTypeNdx		= selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, requirement);
    246 	const VkMemoryAllocateInfo				allocInfo			=
    247 	{
    248 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType	sType
    249 		pNext,									//	const void*		pNext
    250 		memReqs.size,							//	VkDeviceSize	allocationSize
    251 		memoryTypeNdx,							//	deUint32		memoryTypeIndex
    252 	};
    253 	Move<VkDeviceMemory>					mem					= allocateMemory(vkd, device, &allocInfo);
    254 	MovePtr<HostPtr>						hostPtr;
    255 
    256 	if (requirement & MemoryRequirement::HostVisible)
    257 	{
    258 		DE_ASSERT(isHostVisibleMemory(memoryProperties, allocInfo.memoryTypeIndex));
    259 		hostPtr = MovePtr<HostPtr>(new HostPtr(vkd, device, *mem, 0u, allocInfo.allocationSize, 0u));
    260 	}
    261 
    262 	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
    263 }
    264 
    265 de::MovePtr<Allocation> allocateDedicated (const InstanceInterface&	vki,
    266 										   const DeviceInterface&	vkd,
    267 										   const VkPhysicalDevice&	physDevice,
    268 										   const VkDevice			device,
    269 										   const VkBuffer			buffer,
    270 										   MemoryRequirement		requirement)
    271 {
    272 	const VkMemoryRequirements				memoryRequirements		= getBufferMemoryRequirements(vkd, device, buffer);
    273 	const VkMemoryDedicatedAllocateInfo		dedicatedAllocationInfo	=
    274 	{
    275 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,				// VkStructureType		sType
    276 		DE_NULL,															// const void*			pNext
    277 		DE_NULL,															// VkImage				image
    278 		buffer																// VkBuffer				buffer
    279 	};
    280 
    281 	return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
    282 }
    283 
    284 de::MovePtr<Allocation> allocateDedicated (const InstanceInterface&	vki,
    285 										   const DeviceInterface&	vkd,
    286 										   const VkPhysicalDevice&	physDevice,
    287 										   const VkDevice			device,
    288 										   const VkImage			image,
    289 										   MemoryRequirement		requirement)
    290 {
    291 	const VkMemoryRequirements				memoryRequirements		= getImageMemoryRequirements(vkd, device, image);
    292 	const VkMemoryDedicatedAllocateInfo		dedicatedAllocationInfo	=
    293 	{
    294 		VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,			// VkStructureType		sType
    295 		DE_NULL,														// const void*			pNext
    296 		image,															// VkImage				image
    297 		DE_NULL															// VkBuffer				buffer
    298 	};
    299 
    300 	return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo);
    301 }
    302 
    303 void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
    304 {
    305 	void* hostPtr = DE_NULL;
    306 	VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
    307 	TCU_CHECK(hostPtr);
    308 	return hostPtr;
    309 }
    310 
    311 void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
    312 {
    313 	const VkMappedMemoryRange	range	=
    314 	{
    315 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
    316 		DE_NULL,
    317 		memory,
    318 		offset,
    319 		size
    320 	};
    321 
    322 	VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
    323 }
    324 
    325 void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
    326 {
    327 	const VkMappedMemoryRange	range	=
    328 	{
    329 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
    330 		DE_NULL,
    331 		memory,
    332 		offset,
    333 		size
    334 	};
    335 
    336 	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
    337 }
    338 
    339 deUint32 getCompatibleMemoryTypes (const VkPhysicalDeviceMemoryProperties& deviceMemProps, MemoryRequirement requirement)
    340 {
    341 	deUint32	compatibleTypes	= 0u;
    342 
    343 	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
    344 	{
    345 		if (requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
    346 			compatibleTypes |= (1u << memoryTypeNdx);
    347 	}
    348 
    349 	return compatibleTypes;
    350 }
    351 
    352 void bindImagePlaneMemory (const DeviceInterface&	vkd,
    353 						   VkDevice					device,
    354 						   VkImage					image,
    355 						   VkDeviceMemory			memory,
    356 						   VkDeviceSize				memoryOffset,
    357 						   VkImageAspectFlagBits	planeAspect)
    358 {
    359 	const VkBindImagePlaneMemoryInfo	planeInfo	=
    360 	{
    361 		VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR,
    362 		DE_NULL,
    363 		planeAspect
    364 	};
    365 	const VkBindImageMemoryInfo			coreInfo	=
    366 	{
    367 		VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR,
    368 		&planeInfo,
    369 		image,
    370 		memory,
    371 		memoryOffset,
    372 	};
    373 
    374 	VK_CHECK(vkd.bindImageMemory2(device, 1u, &coreInfo));
    375 }
    376 
    377 } // vk
    378