1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "VkDeviceMemory.hpp"
16 #include "VkBuffer.hpp"
17 #include "VkImage.hpp"
18
19 #include "VkConfig.h"
20
21 namespace vk {
22
23 // Base abstract interface for a device memory implementation.
24 class DeviceMemory::ExternalBase
25 {
26 public:
27 virtual ~ExternalBase() = default;
28
29 // Allocate the memory according to |size|. On success return VK_SUCCESS
30 // and sets |*pBuffer|.
31 virtual VkResult allocate(size_t size, void **pBuffer) = 0;
32
33 // Deallocate previously allocated memory at |buffer|.
34 virtual void deallocate(void *buffer, size_t size) = 0;
35
36 // Return the handle type flag bit supported by this implementation.
37 // A value of 0 corresponds to non-external memory.
38 virtual VkExternalMemoryHandleTypeFlagBits getFlagBit() const = 0;
39
40 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
exportFd(int * pFd) const41 virtual VkResult exportFd(int *pFd) const
42 {
43 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
44 }
45 #endif
46
47 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
exportAhb(struct AHardwareBuffer ** pAhb) const48 virtual VkResult exportAhb(struct AHardwareBuffer **pAhb) const
49 {
50 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
51 }
52 #endif
53
54 protected:
55 ExternalBase() = default;
56 };
57
58 // Small class describing a given DeviceMemory::ExternalBase derived class.
59 // |typeFlagBit| corresponds to the external memory handle type.
60 // |instanceSize| is the size of each class instance in bytes.
61 // |instanceInit| is a function pointer used to initialize an instance inplace
62 // according to a |pAllocateInfo| parameter.
63 class ExternalMemoryTraits
64 {
65 public:
66 VkExternalMemoryHandleTypeFlagBits typeFlagBit;
67 size_t instanceSize;
68 void (*instanceInit)(void *external, const VkMemoryAllocateInfo *pAllocateInfo);
69 };
70
71 // Template function that parses a |pAllocateInfo.pNext| chain to verify that
72 // it asks for the creation or import of a memory type managed by implementation
73 // class T. On success, return true and sets |pTraits| accordingly. Otherwise
74 // return false.
75 template<typename T>
parseCreateInfo(const VkMemoryAllocateInfo * pAllocateInfo,ExternalMemoryTraits * pTraits)76 static bool parseCreateInfo(const VkMemoryAllocateInfo *pAllocateInfo,
77 ExternalMemoryTraits *pTraits)
78 {
79 if(T::supportsAllocateInfo(pAllocateInfo))
80 {
81 pTraits->typeFlagBit = T::typeFlagBit;
82 pTraits->instanceSize = sizeof(T);
83 pTraits->instanceInit = [](void *external,
84 const VkMemoryAllocateInfo *pAllocateInfo) {
85 new(external) T(pAllocateInfo);
86 };
87 return true;
88 }
89 return false;
90 }
91
92 // DeviceMemory::ExternalBase implementation that uses host memory.
93 // Not really external, but makes everything simpler.
94 class DeviceMemoryHostExternalBase : public DeviceMemory::ExternalBase
95 {
96 public:
97 // Does not support any external memory type at all.
98 static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
99
100 // Always return true as is used as a fallback in findTraits() below.
supportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)101 static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
102 {
103 return true;
104 }
105
DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo * pAllocateInfo)106 DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo *pAllocateInfo) {}
107
allocate(size_t size,void ** pBuffer)108 VkResult allocate(size_t size, void **pBuffer) override
109 {
110 void *buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
111 if(!buffer)
112 {
113 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
114 }
115
116 *pBuffer = buffer;
117 return VK_SUCCESS;
118 }
119
deallocate(void * buffer,size_t size)120 void deallocate(void *buffer, size_t size) override
121 {
122 vk::deallocate(buffer, DEVICE_MEMORY);
123 }
124
getFlagBit() const125 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
126 {
127 return typeFlagBit;
128 }
129 };
130
131 } // namespace vk
132
133 // Host-allocated memory and host-mapped foreign memory
134 class ExternalMemoryHost : public vk::DeviceMemory::ExternalBase
135 {
136 public:
137 struct AllocateInfo
138 {
139 bool supported = false;
140 void *hostPointer = nullptr;
141
142 AllocateInfo() = default;
143
AllocateInfoExternalMemoryHost::AllocateInfo144 AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
145 {
146 const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
147 while(createInfo)
148 {
149 switch(createInfo->sType)
150 {
151 case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
152 {
153 const auto *importInfo = reinterpret_cast<const VkImportMemoryHostPointerInfoEXT *>(createInfo);
154
155 if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT && importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT)
156 {
157 UNSUPPORTED("importInfo->handleType");
158 }
159 hostPointer = importInfo->pHostPointer;
160 supported = true;
161 break;
162 }
163 default:
164 break;
165 }
166 createInfo = createInfo->pNext;
167 }
168 }
169 };
170
171 static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT);
172
supportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)173 static bool supportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
174 {
175 AllocateInfo info(pAllocateInfo);
176 return info.supported;
177 }
178
ExternalMemoryHost(const VkMemoryAllocateInfo * pAllocateInfo)179 explicit ExternalMemoryHost(const VkMemoryAllocateInfo *pAllocateInfo)
180 : allocateInfo(pAllocateInfo)
181 {
182 }
183
allocate(size_t size,void ** pBuffer)184 VkResult allocate(size_t size, void **pBuffer) override
185 {
186 if(allocateInfo.supported)
187 {
188 *pBuffer = allocateInfo.hostPointer;
189 return VK_SUCCESS;
190 }
191 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
192 }
193
deallocate(void * buffer,size_t size)194 void deallocate(void *buffer, size_t size) override
195 {}
196
getFlagBit() const197 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
198 {
199 return typeFlagBit;
200 }
201
202 private:
203 AllocateInfo allocateInfo;
204 };
205
206 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
207 # if defined(__linux__) || defined(__ANDROID__)
208 # include "VkDeviceMemoryExternalLinux.hpp"
209 # else
210 # error "Missing VK_KHR_external_memory_fd implementation for this platform!"
211 # endif
212 #endif
213
214 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
215 # if defined(__ANDROID__)
216 # include "VkDeviceMemoryExternalAndroid.hpp"
217 # else
218 # error "Missing VK_ANDROID_external_memory_android_hardware_buffer implementation for this platform!"
219 # endif
220 #endif
221
222 namespace vk {
223
findTraits(const VkMemoryAllocateInfo * pAllocateInfo,ExternalMemoryTraits * pTraits)224 static void findTraits(const VkMemoryAllocateInfo *pAllocateInfo,
225 ExternalMemoryTraits *pTraits)
226 {
227 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
228 if(parseCreateInfo<OpaqueFdExternalMemory>(pAllocateInfo, pTraits))
229 {
230 return;
231 }
232 #endif
233 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
234 if(parseCreateInfo<AHardwareBufferExternalMemory>(pAllocateInfo, pTraits))
235 {
236 return;
237 }
238 #endif
239 if(parseCreateInfo<ExternalMemoryHost>(pAllocateInfo, pTraits))
240 {
241 return;
242 }
243 parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
244 }
245
DeviceMemory(const VkMemoryAllocateInfo * pAllocateInfo,void * mem)246 DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem)
247 : size(pAllocateInfo->allocationSize)
248 , memoryTypeIndex(pAllocateInfo->memoryTypeIndex)
249 , external(reinterpret_cast<ExternalBase *>(mem))
250 {
251 ASSERT(size);
252
253 ExternalMemoryTraits traits;
254 findTraits(pAllocateInfo, &traits);
255 traits.instanceInit(external, pAllocateInfo);
256 }
257
destroy(const VkAllocationCallbacks * pAllocator)258 void DeviceMemory::destroy(const VkAllocationCallbacks *pAllocator)
259 {
260 if(buffer)
261 {
262 external->deallocate(buffer, size);
263 buffer = nullptr;
264 }
265 external->~ExternalBase(); // Call virtual destructor in place.
266 vk::deallocate(external, pAllocator);
267 }
268
ComputeRequiredAllocationSize(const VkMemoryAllocateInfo * pAllocateInfo)269 size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pAllocateInfo)
270 {
271 ExternalMemoryTraits traits;
272 findTraits(pAllocateInfo, &traits);
273 return traits.instanceSize;
274 }
275
allocate()276 VkResult DeviceMemory::allocate()
277 {
278 if(size > MAX_MEMORY_ALLOCATION_SIZE)
279 {
280 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
281 }
282
283 VkResult result = VK_SUCCESS;
284 if(!buffer)
285 {
286 result = external->allocate(size, &buffer);
287 }
288 return result;
289 }
290
map(VkDeviceSize pOffset,VkDeviceSize pSize,void ** ppData)291 VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void **ppData)
292 {
293 *ppData = getOffsetPointer(pOffset);
294
295 return VK_SUCCESS;
296 }
297
getCommittedMemoryInBytes() const298 VkDeviceSize DeviceMemory::getCommittedMemoryInBytes() const
299 {
300 return size;
301 }
302
getOffsetPointer(VkDeviceSize pOffset) const303 void *DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const
304 {
305 ASSERT(buffer);
306
307 return reinterpret_cast<char *>(buffer) + pOffset;
308 }
309
checkExternalMemoryHandleType(VkExternalMemoryHandleTypeFlags supportedHandleTypes) const310 bool DeviceMemory::checkExternalMemoryHandleType(
311 VkExternalMemoryHandleTypeFlags supportedHandleTypes) const
312 {
313 if(!supportedHandleTypes)
314 {
315 // This image or buffer does not need to be stored on external
316 // memory, so this check should always pass.
317 return true;
318 }
319 VkExternalMemoryHandleTypeFlagBits handle_type_bit = external->getFlagBit();
320 if(!handle_type_bit)
321 {
322 // This device memory is not external and can accomodate
323 // any image or buffer as well.
324 return true;
325 }
326 // Return true only if the external memory type is compatible with the
327 // one specified during VkCreate{Image,Buffer}(), through a
328 // VkExternalMemory{Image,Buffer}AllocateInfo struct.
329 return (supportedHandleTypes & handle_type_bit) != 0;
330 }
331
332 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
exportFd(int * pFd) const333 VkResult DeviceMemory::exportFd(int *pFd) const
334 {
335 return external->exportFd(pFd);
336 }
337 #endif
338
339 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
exportAhb(struct AHardwareBuffer ** pAhb) const340 VkResult DeviceMemory::exportAhb(struct AHardwareBuffer **pAhb) const
341 {
342 return external->exportAhb(pAhb);
343 }
344
getAhbProperties(const struct AHardwareBuffer * buffer,VkAndroidHardwareBufferPropertiesANDROID * pProperties)345 VkResult DeviceMemory::getAhbProperties(const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
346 {
347 return AHardwareBufferExternalMemory::getAhbProperties(buffer, pProperties);
348 }
349 #endif
350
351 } // namespace vk
352