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 57HostPtr::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 65HostPtr::~HostPtr (void) 66{ 67 m_vkd.unmapMemory(m_device, m_memory); 68} 69 70deUint32 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 81bool 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 91Allocation::Allocation (VkDeviceMemory memory, VkDeviceSize offset, void* hostPtr) 92 : m_memory (memory) 93 , m_offset (offset) 94 , m_hostPtr (hostPtr) 95{ 96} 97 98Allocation::~Allocation (void) 99{ 100} 101 102// MemoryRequirement 103 104const MemoryRequirement MemoryRequirement::Any = MemoryRequirement(0x0u); 105const MemoryRequirement MemoryRequirement::HostVisible = MemoryRequirement(MemoryRequirement::FLAG_HOST_VISIBLE); 106const MemoryRequirement MemoryRequirement::Coherent = MemoryRequirement(MemoryRequirement::FLAG_COHERENT); 107const MemoryRequirement MemoryRequirement::LazilyAllocated = MemoryRequirement(MemoryRequirement::FLAG_LAZY_ALLOCATION); 108 109bool MemoryRequirement::matchesHeap (VkMemoryPropertyFlags heapFlags) const 110{ 111 // sanity check 112 if ((m_flags & FLAG_COHERENT) && !(m_flags & FLAG_HOST_VISIBLE)) 113 DE_FATAL("Coherent memory must be host-visible"); 114 if ((m_flags & FLAG_HOST_VISIBLE) && (m_flags & FLAG_LAZY_ALLOCATION)) 115 DE_FATAL("Lazily allocated memory cannot be mappable"); 116 117 // host-visible 118 if ((m_flags & FLAG_HOST_VISIBLE) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) 119 return false; 120 121 // coherent 122 if ((m_flags & FLAG_COHERENT) && !(heapFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) 123 return false; 124 125 // lazy 126 if ((m_flags & FLAG_LAZY_ALLOCATION) && !(heapFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)) 127 return false; 128 129 return true; 130} 131 132MemoryRequirement::MemoryRequirement (deUint32 flags) 133 : m_flags(flags) 134{ 135} 136 137// SimpleAllocator 138 139class SimpleAllocation : public Allocation 140{ 141public: 142 SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr); 143 virtual ~SimpleAllocation (void); 144 145private: 146 const Unique<VkDeviceMemory> m_memHolder; 147 const UniquePtr<HostPtr> m_hostPtr; 148}; 149 150SimpleAllocation::SimpleAllocation (Move<VkDeviceMemory> mem, MovePtr<HostPtr> hostPtr) 151 : Allocation (*mem, (VkDeviceSize)0, hostPtr ? hostPtr->get() : DE_NULL) 152 , m_memHolder (mem) 153 , m_hostPtr (hostPtr) 154{ 155} 156 157SimpleAllocation::~SimpleAllocation (void) 158{ 159} 160 161SimpleAllocator::SimpleAllocator (const DeviceInterface& vk, VkDevice device, const VkPhysicalDeviceMemoryProperties& deviceMemProps) 162 : m_vk (vk) 163 , m_device (device) 164 , m_memProps(deviceMemProps) 165{ 166} 167 168MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryAllocateInfo& allocInfo, VkDeviceSize alignment) 169{ 170 DE_UNREF(alignment); 171 172 Move<VkDeviceMemory> mem = allocateMemory(m_vk, m_device, &allocInfo); 173 MovePtr<HostPtr> hostPtr; 174 175 if (isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex)) 176 hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u)); 177 178 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr)); 179} 180 181MovePtr<Allocation> SimpleAllocator::allocate (const VkMemoryRequirements& memReqs, MemoryRequirement requirement) 182{ 183 const deUint32 memoryTypeNdx = selectMatchingMemoryType(m_memProps, memReqs.memoryTypeBits, requirement); 184 const VkMemoryAllocateInfo allocInfo = 185 { 186 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType; 187 DE_NULL, // const void* pNext; 188 memReqs.size, // VkDeviceSize allocationSize; 189 memoryTypeNdx, // deUint32 memoryTypeIndex; 190 }; 191 192 Move<VkDeviceMemory> mem = allocateMemory(m_vk, m_device, &allocInfo); 193 MovePtr<HostPtr> hostPtr; 194 195 if (requirement & MemoryRequirement::HostVisible) 196 { 197 DE_ASSERT(isHostVisibleMemory(m_memProps, allocInfo.memoryTypeIndex)); 198 hostPtr = MovePtr<HostPtr>(new HostPtr(m_vk, m_device, *mem, 0u, allocInfo.allocationSize, 0u)); 199 } 200 201 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr)); 202} 203 204static MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki, 205 const DeviceInterface& vkd, 206 const VkPhysicalDevice& physDevice, 207 const VkDevice device, 208 const VkMemoryRequirements& memReqs, 209 const MemoryRequirement requirement, 210 const void* pNext) 211{ 212 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vki, physDevice); 213 const deUint32 memoryTypeNdx = selectMatchingMemoryType(memoryProperties, memReqs.memoryTypeBits, requirement); 214 const VkMemoryAllocateInfo allocInfo = 215 { 216 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType 217 pNext, // const void* pNext 218 memReqs.size, // VkDeviceSize allocationSize 219 memoryTypeNdx, // deUint32 memoryTypeIndex 220 }; 221 Move<VkDeviceMemory> mem = allocateMemory(vkd, device, &allocInfo); 222 MovePtr<HostPtr> hostPtr; 223 224 if (requirement & MemoryRequirement::HostVisible) 225 { 226 DE_ASSERT(isHostVisibleMemory(memoryProperties, allocInfo.memoryTypeIndex)); 227 hostPtr = MovePtr<HostPtr>(new HostPtr(vkd, device, *mem, 0u, allocInfo.allocationSize, 0u)); 228 } 229 230 return MovePtr<Allocation>(new SimpleAllocation(mem, hostPtr)); 231} 232 233de::MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki, 234 const DeviceInterface& vkd, 235 const VkPhysicalDevice& physDevice, 236 const VkDevice device, 237 const VkBuffer buffer, 238 MemoryRequirement requirement) 239{ 240 const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer); 241 const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocationInfo = 242 { 243 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, // VkStructureType sType 244 DE_NULL, // const void* pNext 245 DE_NULL, // VkImage image 246 buffer // VkBuffer buffer 247 }; 248 249 return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo); 250} 251 252de::MovePtr<Allocation> allocateDedicated (const InstanceInterface& vki, 253 const DeviceInterface& vkd, 254 const VkPhysicalDevice& physDevice, 255 const VkDevice device, 256 const VkImage image, 257 MemoryRequirement requirement) 258{ 259 const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image); 260 const VkMemoryDedicatedAllocateInfoKHR dedicatedAllocationInfo = 261 { 262 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, // VkStructureType sType 263 DE_NULL, // const void* pNext 264 image, // VkImage image 265 DE_NULL // VkBuffer buffer 266 }; 267 268 return allocateDedicated(vki, vkd, physDevice, device, memoryRequirements, requirement, &dedicatedAllocationInfo); 269} 270 271void* mapMemory (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags) 272{ 273 void* hostPtr = DE_NULL; 274 VK_CHECK(vkd.mapMemory(device, mem, offset, size, flags, &hostPtr)); 275 TCU_CHECK(hostPtr); 276 return hostPtr; 277} 278 279void flushMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size) 280{ 281 const VkMappedMemoryRange range = 282 { 283 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 284 DE_NULL, 285 memory, 286 offset, 287 size 288 }; 289 290 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &range)); 291} 292 293void invalidateMappedMemoryRange (const DeviceInterface& vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size) 294{ 295 const VkMappedMemoryRange range = 296 { 297 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 298 DE_NULL, 299 memory, 300 offset, 301 size 302 }; 303 304 VK_CHECK(vkd.invalidateMappedMemoryRanges(device, 1u, &range)); 305} 306 307deUint32 getCompatibleMemoryTypes (const VkPhysicalDeviceMemoryProperties& deviceMemProps, MemoryRequirement requirement) 308{ 309 deUint32 compatibleTypes = 0u; 310 311 for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++) 312 { 313 if (requirement.matchesHeap(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags)) 314 compatibleTypes |= (1u << memoryTypeNdx); 315 } 316 317 return compatibleTypes; 318} 319 320void bindImagePlaneMemory (const DeviceInterface& vkd, 321 VkDevice device, 322 VkImage image, 323 VkDeviceMemory memory, 324 VkDeviceSize memoryOffset, 325 VkImageAspectFlagBits planeAspect) 326{ 327 const VkBindImagePlaneMemoryInfoKHR planeInfo = 328 { 329 VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR, 330 DE_NULL, 331 planeAspect 332 }; 333 const VkBindImageMemoryInfoKHR coreInfo = 334 { 335 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR, 336 &planeInfo, 337 image, 338 memory, 339 memoryOffset, 340 }; 341 342 VK_CHECK(vkd.bindImageMemory2KHR(device, 1u, &coreInfo)); 343} 344 345} // vk 346