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 void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
     58 {
     59 	void* hostPtr = DE_NULL;
     60 	VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr));
     61 	TCU_CHECK(hostPtr);
     62 	return hostPtr;
     63 }
     64 
     65 HostPtr::HostPtr (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags)
     66 	: m_vkd		(vkd)
     67 	, m_device	(device)
     68 	, m_memory	(memory)
     69 	, m_ptr		(mapMemory(vkd, device, memory, offset, size, flags))
     70 {
     71 }
     72 
     73 HostPtr::~HostPtr (void)
     74 {
     75 	m_vkd.unmapMemory(m_device, m_memory);
     76 }
     77 
     78 deUint32 selectMatchingMemoryType (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 allowedMemTypeBits, MemoryRequirement requirement)
     79 {
     80 	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
     81 	{
     82 		if ((allowedMemTypeBits & (1u << memoryTypeNdx)) != 0 &&
     83 			requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags))
     84 			return memoryTypeNdx;
     85 	}
     86 
     87 	TCU_THROW(NotSupportedError, "No compatible memory type found");
     88 }
     89 
     90 bool isHostVisibleMemory (const VkPhysicalDeviceMemoryProperties& deviceMemProps, deUint32 memoryTypeNdx)
     91 {
     92 	DE_ASSERT(memoryTypeNdx < deviceMemProps.memoryTypeCount);
     93 	return (deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0u;
     94 }
     95 
     96 } // anonymous
     97 
     98 // Allocation
     99 
    100 Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr)
    101 	: m_memory	(memory)
    102 	, m_offset	(offset)
    103 	, m_hostPtr	(hostPtr)
    104 {
    105 }
    106 
    107 Allocation::~Allocation (void)
    108 {
    109 }
    110 
    111 // MemoryRequirement
    112 
    113 const MemoryRequirement MemoryRequirement::Any				= MemoryRequirement(0x0u);
    114 const MemoryRequirement MemoryRequirement::HostVisible		= MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE);
    115 const MemoryRequirement MemoryRequirement::Coherent			= MemoryRequirement(MemoryRequirement::FLAG_COHERENT);
    116 const MemoryRequirement MemoryRequirement::LazilyAllocated	= MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION);
    117 
    118 bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const
    119 {
    120 	// sanity check
    121 	if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE))
    122 		DE_FATAL("Coherent memory must be host-visible");
    123 	if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION))
    124 		DE_FATAL("Lazily allocated memory cannot be mappable");
    125 
    126 	// host-visible
    127 	if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
    128 		return false;
    129 
    130 	// coherent
    131 	if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
    132 		return false;
    133 
    134 	// lazy
    135 	if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT))
    136 		return false;
    137 
    138 	return true;
    139 }
    140 
    141 MemoryRequirement::MemoryRequirement (deUint32 flags)
    142 	: m_flags(flags)
    143 {
    144 }
    145 
    146 // SimpleAllocator
    147 
    148 class SimpleAllocation : public Allocation
    149 {
    150 public:
    151 									SimpleAllocation	(Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr);
    152 	virtual							~SimpleAllocation	(void);
    153 
    154 private:
    155 	const Unique<VkDeviceMemory>	m_memHolder;
    156 	const UniquePtr<HostPtr>		m_hostPtr;
    157 };
    158 
    159 SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr)
    160 	: Allocation	(*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL)
    161 	, m_memHolder	(mem)
    162 	, m_hostPtr		(hostPtr)
    163 {
    164 }
    165 
    166 SimpleAllocation::~SimpleAllocation (void)
    167 {
    168 }
    169 
    170 SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps)
    171 	: m_vk		(vk)
    172 	, m_device	(device)
    173 	, m_memProps(deviceMemProps)
    174 {
    175 }
    176 
    177 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment)
    178 {
    179 	DE_UNREF(alignment);
    180 
    181 	Move<VkDeviceMemory>	mem		= allocateMemory(m_vk, m_device, &allocInfo);
    182 	MovePtr<HostPtr>		hostPtr;
    183 
    184 	if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex))
    185 		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
    186 
    187 	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
    188 }
    189 
    190 MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement)
    191 {
    192 	const deUint32				memoryTypeNdx	= selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement);
    193 	const VkMemoryAllocateInfo	allocInfo		=
    194 	{
    195 		VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	//	VkStructureType			sType;
    196 		DE_NULL,								//	const void*				pNext;
    197 		memReqs.size,							//	VkDeviceSize			allocationSize;
    198 		memoryTypeNdx,							//	deUint32				memoryTypeIndex;
    199 	};
    200 
    201 	Move<VkDeviceMemory>		mem				= allocateMemory(m_vk, m_device, &allocInfo);
    202 	MovePtr<HostPtr>			hostPtr;
    203 
    204 	if (requirement & MemoryRequirement::HostVisible)
    205 	{
    206 		DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex));
    207 		hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u));
    208 	}
    209 
    210 	return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr));
    211 }
    212 
    213 void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
    214 {
    215 	const VkMappedMemoryRange	range	=
    216 	{
    217 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
    218 		DE_NULL,
    219 		memory,
    220 		offset,
    221 		size
    222 	};
    223 
    224 	VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range));
    225 }
    226 
    227 void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size)
    228 {
    229 	const VkMappedMemoryRange	range	=
    230 	{
    231 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
    232 		DE_NULL,
    233 		memory,
    234 		offset,
    235 		size
    236 	};
    237 
    238 	VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range));
    239 }
    240 
    241 } // vk
    242