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