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 "VkDevice.hpp"
18 #include "VkDeviceMemoryExternalBase.hpp"
19 #include "VkImage.hpp"
20 #include "VkStringify.hpp"
21
22 #include "VkConfig.hpp"
23
24 namespace vk {
25
26 // Small class describing a given DeviceMemory::ExternalBase derived class.
27 // |typeFlagBit| corresponds to the external memory handle type.
28 // |instanceSize| is the size of each class instance in bytes.
29 // |instanceInit| is a function pointer used to initialize an instance inplace
30 // according to a |pAllocateInfo| parameter.
31 class ExternalMemoryTraits
32 {
33 public:
34 VkExternalMemoryHandleTypeFlagBits typeFlagBit;
35 size_t instanceSize;
36 void (*instanceInit)(void *external, const VkMemoryAllocateInfo *pAllocateInfo);
37 };
38
39 // Template function that parses a |pAllocateInfo.pNext| chain to verify that
40 // it asks for the creation or import of a memory type managed by implementation
41 // class T. On success, return true and sets |pTraits| accordingly. Otherwise
42 // return false.
43 template<typename T>
parseCreateInfo(const VkMemoryAllocateInfo * pAllocateInfo,ExternalMemoryTraits * pTraits)44 static bool parseCreateInfo(const VkMemoryAllocateInfo *pAllocateInfo,
45 ExternalMemoryTraits *pTraits)
46 {
47 if(T::SupportsAllocateInfo(pAllocateInfo))
48 {
49 pTraits->typeFlagBit = T::typeFlagBit;
50 pTraits->instanceSize = sizeof(T);
51 pTraits->instanceInit = [](void *external,
52 const VkMemoryAllocateInfo *pAllocateInfo) {
53 new(external) T(pAllocateInfo);
54 };
55 return true;
56 }
57 return false;
58 }
59
60 // DeviceMemory::ExternalBase implementation that uses host memory.
61 // Not really external, but makes everything simpler.
62 class DeviceMemoryHostExternalBase : public DeviceMemory::ExternalBase
63 {
64 public:
65 // Does not support any external memory type at all.
66 static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = (VkExternalMemoryHandleTypeFlagBits)0;
67
68 // Always return true as is used as a fallback in findTraits() below.
SupportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)69 static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
70 {
71 return true;
72 }
73
DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo * pAllocateInfo)74 DeviceMemoryHostExternalBase(const VkMemoryAllocateInfo *pAllocateInfo) {}
75
allocate(size_t size,void ** pBuffer)76 VkResult allocate(size_t size, void **pBuffer) override
77 {
78 buffer = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
79 if(!buffer)
80 {
81 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
82 }
83
84 *pBuffer = buffer;
85 return VK_SUCCESS;
86 }
87
deallocate(void *,size_t size)88 void deallocate(void * /* buffer */, size_t size) override
89 {
90 vk::deallocate(buffer, DEVICE_MEMORY);
91 buffer = nullptr;
92 }
93
getFlagBit() const94 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
95 {
96 return typeFlagBit;
97 }
98
99 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
getMemoryObjectId() const100 uint64_t getMemoryObjectId() const override
101 {
102 return (uint64_t)buffer;
103 }
104 #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT
105
106 private:
107 void *buffer = nullptr;
108 };
109
110 } // namespace vk
111
112 // Host-allocated memory and host-mapped foreign memory
113 class ExternalMemoryHost : public vk::DeviceMemory::ExternalBase
114 {
115 public:
116 struct AllocateInfo
117 {
118 bool supported = false;
119 void *hostPointer = nullptr;
120
121 AllocateInfo() = default;
122
AllocateInfoExternalMemoryHost::AllocateInfo123 AllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
124 {
125 const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
126 while(createInfo)
127 {
128 switch(createInfo->sType)
129 {
130 case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT:
131 {
132 const auto *importInfo = reinterpret_cast<const VkImportMemoryHostPointerInfoEXT *>(createInfo);
133
134 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)
135 {
136 UNSUPPORTED("importInfo->handleType");
137 }
138 hostPointer = importInfo->pHostPointer;
139 supported = true;
140 break;
141 }
142 default:
143 break;
144 }
145 createInfo = createInfo->pNext;
146 }
147 }
148 };
149
150 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);
151
SupportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)152 static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
153 {
154 AllocateInfo info(pAllocateInfo);
155 return info.supported;
156 }
157
ExternalMemoryHost(const VkMemoryAllocateInfo * pAllocateInfo)158 explicit ExternalMemoryHost(const VkMemoryAllocateInfo *pAllocateInfo)
159 : allocateInfo(pAllocateInfo)
160 {
161 }
162
allocate(size_t size,void ** pBuffer)163 VkResult allocate(size_t size, void **pBuffer) override
164 {
165 if(allocateInfo.supported)
166 {
167 *pBuffer = allocateInfo.hostPointer;
168 return VK_SUCCESS;
169 }
170 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
171 }
172
deallocate(void * buffer,size_t size)173 void deallocate(void *buffer, size_t size) override
174 {}
175
getFlagBit() const176 VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
177 {
178 return typeFlagBit;
179 }
180
181 private:
182 AllocateInfo allocateInfo;
183 };
184
185 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
186
187 // Helper struct to parse the VkMemoryAllocateInfo.pNext chain and
188 // extract relevant information related to the handle type supported
189 // by this DeviceMemory;:ExternalBase subclass.
190 struct OpaqueFdAllocateInfo
191 {
192 bool importFd = false;
193 bool exportFd = false;
194 int fd = -1;
195
196 OpaqueFdAllocateInfo() = default;
197
198 // Parse the VkMemoryAllocateInfo.pNext chain to initialize an OpaqueFdAllocateInfo.
OpaqueFdAllocateInfoOpaqueFdAllocateInfo199 OpaqueFdAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
200 {
201 const auto *createInfo = reinterpret_cast<const VkBaseInStructure *>(pAllocateInfo->pNext);
202 while(createInfo)
203 {
204 switch(createInfo->sType)
205 {
206 case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR:
207 {
208 const auto *importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR *>(createInfo);
209
210 if(importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
211 {
212 UNSUPPORTED("VkImportMemoryFdInfoKHR::handleType %d", int(importInfo->handleType));
213 }
214 importFd = true;
215 fd = importInfo->fd;
216 }
217 break;
218 case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO:
219 {
220 const auto *exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo *>(createInfo);
221
222 if(exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT)
223 {
224 UNSUPPORTED("VkExportMemoryAllocateInfo::handleTypes %d", int(exportInfo->handleTypes));
225 }
226 exportFd = true;
227 }
228 break;
229 case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO:
230 // This can safely be ignored, as the Vulkan spec mentions:
231 // "If the pNext chain includes a VkMemoryDedicatedAllocateInfo structure, then that structure
232 // includes a handle of the sole buffer or image resource that the memory *can* be bound to."
233 break;
234 default:
235 WARN("VkMemoryAllocateInfo->pNext sType = %s", vk::Stringify(createInfo->sType).c_str());
236 }
237 createInfo = createInfo->pNext;
238 }
239 }
240 };
241
242 # if defined(__APPLE__)
243 # include "VkDeviceMemoryExternalMac.hpp"
244 # elif defined(__linux__) && !defined(__ANDROID__)
245 # include "VkDeviceMemoryExternalLinux.hpp"
246 # else
247 # error "Missing VK_KHR_external_memory_fd implementation for this platform!"
248 # endif
249 #endif
250
251 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
252 # if defined(__ANDROID__)
253 # include "VkDeviceMemoryExternalAndroid.hpp"
254 # else
255 # error "Missing VK_ANDROID_external_memory_android_hardware_buffer implementation for this platform!"
256 # endif
257 #endif
258
259 #if VK_USE_PLATFORM_FUCHSIA
260 # include "VkDeviceMemoryExternalFuchsia.hpp"
261 #endif
262
263 namespace vk {
264
findTraits(const VkMemoryAllocateInfo * pAllocateInfo,ExternalMemoryTraits * pTraits)265 static void findTraits(const VkMemoryAllocateInfo *pAllocateInfo,
266 ExternalMemoryTraits *pTraits)
267 {
268 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
269 if(parseCreateInfo<AHardwareBufferExternalMemory>(pAllocateInfo, pTraits))
270 {
271 return;
272 }
273 #endif
274 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
275 if(parseCreateInfo<OpaqueFdExternalMemory>(pAllocateInfo, pTraits))
276 {
277 return;
278 }
279 #endif
280 #if VK_USE_PLATFORM_FUCHSIA
281 if(parseCreateInfo<zircon::VmoExternalMemory>(pAllocateInfo, pTraits))
282 {
283 return;
284 }
285 #endif
286 if(parseCreateInfo<ExternalMemoryHost>(pAllocateInfo, pTraits))
287 {
288 return;
289 }
290 parseCreateInfo<DeviceMemoryHostExternalBase>(pAllocateInfo, pTraits);
291 }
292
DeviceMemory(const VkMemoryAllocateInfo * pAllocateInfo,void * mem,Device * pDevice)293 DeviceMemory::DeviceMemory(const VkMemoryAllocateInfo *pAllocateInfo, void *mem, Device *pDevice)
294 : size(pAllocateInfo->allocationSize)
295 , memoryTypeIndex(pAllocateInfo->memoryTypeIndex)
296 , device(pDevice)
297 {
298 ASSERT(size);
299
300 ExternalMemoryTraits traits;
301 findTraits(pAllocateInfo, &traits);
302 traits.instanceInit(mem, pAllocateInfo);
303 external = reinterpret_cast<ExternalBase *>(mem);
304 external->setDevicePtr(device);
305 }
306
destroy(const VkAllocationCallbacks * pAllocator)307 void DeviceMemory::destroy(const VkAllocationCallbacks *pAllocator)
308 {
309 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
310 device->emitDeviceMemoryReport(external->isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT, external->getMemoryObjectId(), 0 /* size */, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
311 #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT
312 if(buffer)
313 {
314 external->deallocate(buffer, size);
315 buffer = nullptr;
316 }
317 external->~ExternalBase(); // Call virtual destructor in place.
318 vk::deallocate(external, pAllocator);
319 }
320
ComputeRequiredAllocationSize(const VkMemoryAllocateInfo * pAllocateInfo)321 size_t DeviceMemory::ComputeRequiredAllocationSize(const VkMemoryAllocateInfo *pAllocateInfo)
322 {
323 ExternalMemoryTraits traits;
324 findTraits(pAllocateInfo, &traits);
325 return traits.instanceSize;
326 }
327
allocate()328 VkResult DeviceMemory::allocate()
329 {
330 if(size > MAX_MEMORY_ALLOCATION_SIZE)
331 {
332 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
333 device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, size, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */);
334 #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT
335 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
336 }
337
338 VkResult result = VK_SUCCESS;
339 if(!buffer)
340 {
341 result = external->allocate(size, &buffer);
342 }
343 #ifdef SWIFTSHADER_DEVICE_MEMORY_REPORT
344 if(result == VK_SUCCESS)
345 {
346 device->emitDeviceMemoryReport(external->isImport() ? VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT : VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT, external->getMemoryObjectId(), size, VK_OBJECT_TYPE_DEVICE_MEMORY, (uint64_t)(void *)VkDeviceMemory(*this));
347 }
348 else
349 {
350 device->emitDeviceMemoryReport(VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT, 0 /* memoryObjectId */, size, VK_OBJECT_TYPE_DEVICE_MEMORY, 0 /* objectHandle */);
351 }
352 #endif // SWIFTSHADER_DEVICE_MEMORY_REPORT
353 return result;
354 }
355
map(VkDeviceSize pOffset,VkDeviceSize pSize,void ** ppData)356 VkResult DeviceMemory::map(VkDeviceSize pOffset, VkDeviceSize pSize, void **ppData)
357 {
358 *ppData = getOffsetPointer(pOffset);
359
360 return VK_SUCCESS;
361 }
362
getCommittedMemoryInBytes() const363 VkDeviceSize DeviceMemory::getCommittedMemoryInBytes() const
364 {
365 return size;
366 }
367
getOffsetPointer(VkDeviceSize pOffset) const368 void *DeviceMemory::getOffsetPointer(VkDeviceSize pOffset) const
369 {
370 ASSERT(buffer);
371 return reinterpret_cast<char *>(buffer) + pOffset;
372 }
373
checkExternalMemoryHandleType(VkExternalMemoryHandleTypeFlags supportedHandleTypes) const374 bool DeviceMemory::checkExternalMemoryHandleType(
375 VkExternalMemoryHandleTypeFlags supportedHandleTypes) const
376 {
377 if(!supportedHandleTypes)
378 {
379 // This image or buffer does not need to be stored on external
380 // memory, so this check should always pass.
381 return true;
382 }
383 VkExternalMemoryHandleTypeFlagBits handle_type_bit = external->getFlagBit();
384 if(!handle_type_bit)
385 {
386 // This device memory is not external and can accomodate
387 // any image or buffer as well.
388 return true;
389 }
390 // Return true only if the external memory type is compatible with the
391 // one specified during VkCreate{Image,Buffer}(), through a
392 // VkExternalMemory{Image,Buffer}AllocateInfo struct.
393 return (supportedHandleTypes & handle_type_bit) != 0;
394 }
395
hasExternalImageProperties() const396 bool DeviceMemory::hasExternalImageProperties() const
397 {
398 return external && external->hasExternalImageProperties();
399 }
400
externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const401 int DeviceMemory::externalImageRowPitchBytes(VkImageAspectFlagBits aspect) const
402 {
403 if(external)
404 {
405 return external->externalImageRowPitchBytes(aspect);
406 }
407
408 // This function should never be called on non-external memory.
409 ASSERT(false);
410 return -1;
411 }
412
externalImageMemoryOffset(VkImageAspectFlagBits aspect) const413 VkDeviceSize DeviceMemory::externalImageMemoryOffset(VkImageAspectFlagBits aspect) const
414 {
415 if(external)
416 {
417 return external->externalImageMemoryOffset(aspect);
418 }
419
420 // This function should never be called on non-external memory.
421 ASSERT(false);
422 return -1;
423 }
424
425 #if SWIFTSHADER_EXTERNAL_MEMORY_OPAQUE_FD
exportFd(int * pFd) const426 VkResult DeviceMemory::exportFd(int *pFd) const
427 {
428 return external->exportFd(pFd);
429 }
430 #endif
431
432 #if SWIFTSHADER_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER
exportAndroidHardwareBuffer(struct AHardwareBuffer ** pAhb) const433 VkResult DeviceMemory::exportAndroidHardwareBuffer(struct AHardwareBuffer **pAhb) const
434 {
435 if(external->getFlagBit() != VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)
436 {
437 return VK_ERROR_OUT_OF_HOST_MEMORY;
438 }
439 return static_cast<AHardwareBufferExternalMemory *>(external)->exportAndroidHardwareBuffer(pAhb);
440 }
441
GetAndroidHardwareBufferProperties(VkDevice & ahbDevice,const struct AHardwareBuffer * buffer,VkAndroidHardwareBufferPropertiesANDROID * pProperties)442 VkResult DeviceMemory::GetAndroidHardwareBufferProperties(VkDevice &ahbDevice, const struct AHardwareBuffer *buffer, VkAndroidHardwareBufferPropertiesANDROID *pProperties)
443 {
444 return AHardwareBufferExternalMemory::GetAndroidHardwareBufferProperties(ahbDevice, buffer, pProperties);
445 }
446 #endif
447
448 #if VK_USE_PLATFORM_FUCHSIA
exportHandle(zx_handle_t * pHandle) const449 VkResult DeviceMemory::exportHandle(zx_handle_t *pHandle) const
450 {
451 return external->exportHandle(pHandle);
452 }
453 #endif
454
455 } // namespace vk
456