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