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