1 #ifndef _VKMEMUTIL_HPP 2 #define _VKMEMUTIL_HPP 3 /*------------------------------------------------------------------------- 4 * Vulkan CTS Framework 5 * -------------------- 6 * 7 * Copyright (c) 2019 Google Inc. 8 * Copyright (c) 2019 The Khronos Group Inc. 9 * 10 * Licensed under the Apache License, Version 2.0 (the "License"); 11 * you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software 17 * distributed under the License is distributed on an "AS IS" BASIS, 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 * See the License for the specific language governing permissions and 20 * limitations under the License. 21 * 22 *//*! 23 * \file 24 * \brief Memory management utilities. 25 *//*--------------------------------------------------------------------*/ 26 27 #include "vkDefs.hpp" 28 #include "tcuMaybe.hpp" 29 #include "deUniquePtr.hpp" 30 #include "deSharedPtr.hpp" 31 #include <vector> 32 33 namespace vk 34 { 35 36 /*--------------------------------------------------------------------*//*! 37 * \brief Memory allocation interface 38 * 39 * Allocation represents block of device memory and is allocated by 40 * Allocator implementation. Test code should use Allocator for allocating 41 * memory, unless there is a reason not to (for example testing vkAllocMemory). 42 * 43 * Allocation doesn't necessarily correspond to a whole VkDeviceMemory, but 44 * instead it may represent sub-allocation. Thus whenever VkDeviceMemory 45 * (getMemory()) managed by Allocation is passed to Vulkan API calls, 46 * offset given by getOffset() must be used. 47 * 48 * If host-visible memory was requested, host pointer to the memory can 49 * be queried with getHostPtr(). No offset is needed when accessing host 50 * pointer, i.e. the pointer is already adjusted in case of sub-allocation. 51 * 52 * Memory mappings are managed solely by Allocation, i.e. unmapping or 53 * re-mapping VkDeviceMemory owned by Allocation is not allowed. 54 *//*--------------------------------------------------------------------*/ 55 class Allocation 56 { 57 public: 58 virtual ~Allocation(void); 59 60 //! Get VkDeviceMemory backing this allocation getMemory(void) const61 VkDeviceMemory getMemory(void) const 62 { 63 return m_memory; 64 } 65 66 //! Get offset in VkDeviceMemory for this allocation getOffset(void) const67 VkDeviceSize getOffset(void) const 68 { 69 return m_offset; 70 } 71 72 //! Get host pointer for this allocation. Only available for host-visible allocations getHostPtr(void) const73 void *getHostPtr(void) const 74 { 75 DE_ASSERT(m_hostPtr); 76 return m_hostPtr; 77 } 78 79 protected: 80 Allocation(VkDeviceMemory memory, VkDeviceSize offset, void *hostPtr); 81 82 private: 83 const VkDeviceMemory m_memory; 84 const VkDeviceSize m_offset; 85 void *const m_hostPtr; 86 }; 87 88 void flushAlloc(const DeviceInterface &vkd, VkDevice device, const Allocation &alloc); 89 void invalidateAlloc(const DeviceInterface &vkd, VkDevice device, const Allocation &alloc); 90 91 //! Memory allocation requirements 92 class MemoryRequirement 93 { 94 public: 95 static const MemoryRequirement Any; 96 static const MemoryRequirement HostVisible; 97 static const MemoryRequirement Coherent; 98 static const MemoryRequirement LazilyAllocated; 99 static const MemoryRequirement Protected; 100 static const MemoryRequirement Local; 101 static const MemoryRequirement Cached; 102 static const MemoryRequirement NonLocal; 103 static const MemoryRequirement DeviceAddress; 104 static const MemoryRequirement DeviceAddressCaptureReplay; 105 operator |(MemoryRequirement requirement) const106 inline MemoryRequirement operator|(MemoryRequirement requirement) const 107 { 108 return MemoryRequirement(m_flags | requirement.m_flags); 109 } 110 operator &(MemoryRequirement requirement) const111 inline MemoryRequirement operator&(MemoryRequirement requirement) const 112 { 113 return MemoryRequirement(m_flags & requirement.m_flags); 114 } 115 116 bool matchesHeap(VkMemoryPropertyFlags heapFlags) const; 117 operator bool(void) const118 inline operator bool(void) const 119 { 120 return m_flags != 0u; 121 } 122 123 private: 124 explicit MemoryRequirement(uint32_t flags); 125 126 const uint32_t m_flags; 127 128 enum Flags 129 { 130 FLAG_HOST_VISIBLE = 1u << 0u, 131 FLAG_COHERENT = 1u << 1u, 132 FLAG_LAZY_ALLOCATION = 1u << 2u, 133 FLAG_PROTECTED = 1u << 3u, 134 FLAG_LOCAL = 1u << 4u, 135 FLAG_CACHED = 1u << 5u, 136 FLAG_NON_LOCAL = 1u << 6u, 137 FLAG_DEVICE_ADDRESS = 1u << 7u, 138 FLAG_DEVICE_ADDRESS_CAPTURE_REPLAY = 1u << 8u, 139 }; 140 }; 141 142 //! Memory allocator interface 143 class Allocator 144 { 145 public: Allocator(void)146 Allocator(void) 147 { 148 } ~Allocator(void)149 virtual ~Allocator(void) 150 { 151 } 152 153 virtual de::MovePtr<Allocation> allocate(const VkMemoryAllocateInfo &allocInfo, VkDeviceSize alignment) = 0; 154 virtual de::MovePtr<Allocation> allocate(const VkMemoryRequirements &memRequirements, 155 MemoryRequirement requirement) = 0; 156 }; 157 158 //! Allocator that backs every allocation with its own VkDeviceMemory 159 class SimpleAllocator : public Allocator 160 { 161 public: 162 struct OffsetParams 163 { 164 const vk::VkDeviceSize nonCoherentAtomSize; 165 const vk::VkDeviceSize offset; 166 }; 167 typedef tcu::Maybe<OffsetParams> OptionalOffsetParams; 168 169 SimpleAllocator(const DeviceInterface &vk, VkDevice device, const VkPhysicalDeviceMemoryProperties &deviceMemProps, 170 const OptionalOffsetParams &offsetParams = tcu::Nothing); 171 172 de::MovePtr<Allocation> allocate(const VkMemoryAllocateInfo &allocInfo, VkDeviceSize alignment); 173 de::MovePtr<Allocation> allocate(const VkMemoryRequirements &memRequirements, MemoryRequirement requirement); 174 175 private: 176 const DeviceInterface &m_vk; 177 const VkDevice m_device; 178 const VkPhysicalDeviceMemoryProperties m_memProps; 179 const tcu::Maybe<OffsetParams> m_offsetParams; 180 }; 181 182 de::MovePtr<Allocation> allocateExtended(const InstanceInterface &vki, const DeviceInterface &vkd, 183 const VkPhysicalDevice &physDevice, const VkDevice device, 184 const VkMemoryRequirements &memReqs, const MemoryRequirement requirement, 185 const void *pNext); 186 de::MovePtr<Allocation> allocateDedicated(const InstanceInterface &vki, const DeviceInterface &vkd, 187 const VkPhysicalDevice &physDevice, const VkDevice device, 188 const VkBuffer buffer, MemoryRequirement requirement); 189 de::MovePtr<Allocation> allocateDedicated(const InstanceInterface &vki, const DeviceInterface &vkd, 190 const VkPhysicalDevice &physDevice, const VkDevice device, 191 const VkImage image, MemoryRequirement requirement); 192 193 void *mapMemory(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory mem, VkDeviceSize offset, VkDeviceSize size, 194 VkMemoryMapFlags flags); 195 void flushMappedMemoryRange(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, 196 VkDeviceSize size); 197 void invalidateMappedMemoryRange(const DeviceInterface &vkd, VkDevice device, VkDeviceMemory memory, 198 VkDeviceSize offset, VkDeviceSize size); 199 200 uint32_t selectMatchingMemoryType(const VkPhysicalDeviceMemoryProperties &deviceMemProps, uint32_t allowedMemTypeBits, 201 MemoryRequirement requirement); 202 uint32_t getCompatibleMemoryTypes(const VkPhysicalDeviceMemoryProperties &deviceMemProps, 203 MemoryRequirement requirement); 204 #ifdef CTS_USES_VULKANSC 205 uint32_t getSEUSafeMemoryTypes(const VkPhysicalDeviceMemoryProperties &deviceMemProps); 206 #endif // CTS_USES_VULKANSC 207 208 void bindImagePlanesMemory(const vk::DeviceInterface &vkd, const vk::VkDevice device, const vk::VkImage image, 209 const uint32_t numPlanes, std::vector<de::SharedPtr<Allocation>> &allocations, 210 vk::Allocator &allocator, const vk::MemoryRequirement requirement); 211 212 de::MovePtr<Allocation> bindImage(const DeviceInterface &vk, const VkDevice device, Allocator &allocator, 213 const VkImage image, const MemoryRequirement requirement); 214 215 de::MovePtr<Allocation> bindBuffer(const DeviceInterface &vk, const VkDevice device, Allocator &allocator, 216 const VkBuffer buffer, const MemoryRequirement requirement); 217 218 void zeroBuffer(const DeviceInterface &vk, const VkDevice device, const Allocation &alloc, const VkDeviceSize size); 219 220 } // namespace vk 221 222 #endif // _VKMEMUTIL_HPP 223