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 33namespace vk 34{ 35 36using de::UniquePtr; 37using de::MovePtr; 38 39namespace 40{ 41 42class HostPtr 43{ 44public: 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 50private: 51 const DeviceInterface& m_vkd; 52 const VkDevice m_device; 53 const VkDeviceMemory m_memory; 54 void* const m_ptr; 55}; 56 57void* 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 65HostPtr::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 73HostPtr::~HostPtr (void) 74{ 75 m_vkd.unmapMemory(m_device, m_memory); 76} 77 78deUint32 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 90bool 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 100Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr) 101 : m_memory (memory) 102 , m_offset (offset) 103 , m_hostPtr (hostPtr) 104{ 105} 106 107Allocation::~Allocation (void) 108{ 109} 110 111// MemoryRequirement 112 113const MemoryRequirement MemoryRequirement::Any = MemoryRequirement(0x0u); 114const MemoryRequirement MemoryRequirement::HostVisible = MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE); 115const MemoryRequirement MemoryRequirement::Coherent = MemoryRequirement(MemoryRequirement::FLAG_COHERENT); 116const MemoryRequirement MemoryRequirement::LazilyAllocated = MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION); 117 118bool 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 141MemoryRequirement::MemoryRequirement (deUint32 flags) 142 : m_flags(flags) 143{ 144} 145 146// SimpleAllocator 147 148class SimpleAllocation : public Allocation 149{ 150public: 151 SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr); 152 virtual ~SimpleAllocation (void); 153 154private: 155 const Unique<VkDeviceMemory> m_memHolder; 156 const UniquePtr<HostPtr> m_hostPtr; 157}; 158 159SimpleAllocation::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 166SimpleAllocation::~SimpleAllocation (void) 167{ 168} 169 170SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps) 171 : m_vk (vk) 172 , m_device (device) 173 , m_memProps(deviceMemProps) 174{ 175} 176 177MovePtr<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 190MovePtr<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 213void 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 227void 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