1 // Copyright 2019 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 "System/Debug.hpp"
16 #include "System/Linux/MemFd.hpp"
17 
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/mman.h>
21 
22 class OpaqueFdExternalMemory : public vk::DeviceMemory::ExternalBase
23 {
24 public:
25 	static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
26 
SupportsAllocateInfo(const VkMemoryAllocateInfo * pAllocateInfo)27 	static bool SupportsAllocateInfo(const VkMemoryAllocateInfo *pAllocateInfo)
28 	{
29 		OpaqueFdAllocateInfo info(pAllocateInfo);
30 		return info.importFd || info.exportFd;
31 	}
32 
OpaqueFdExternalMemory(const VkMemoryAllocateInfo * pAllocateInfo)33 	explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pAllocateInfo)
34 	    : allocateInfo(pAllocateInfo)
35 	{
36 	}
37 
~OpaqueFdExternalMemory()38 	~OpaqueFdExternalMemory()
39 	{
40 		memfd.close();
41 	}
42 
allocate(size_t size,void ** pBuffer)43 	VkResult allocate(size_t size, void **pBuffer) override
44 	{
45 		if(allocateInfo.importFd)
46 		{
47 			memfd.importFd(allocateInfo.fd);
48 			if(!memfd.isValid())
49 			{
50 				return VK_ERROR_INVALID_EXTERNAL_HANDLE;
51 			}
52 		}
53 		else
54 		{
55 			ASSERT(allocateInfo.exportFd);
56 			static int counter = 0;
57 			char name[40];
58 			snprintf(name, sizeof(name), "SwiftShader.Memory.%d", ++counter);
59 			if(!memfd.allocate(name, size))
60 			{
61 				TRACE("memfd.allocate() returned %s", strerror(errno));
62 				return VK_ERROR_OUT_OF_DEVICE_MEMORY;
63 			}
64 		}
65 		void *addr = memfd.mapReadWrite(0, size);
66 		if(!addr)
67 		{
68 			return VK_ERROR_MEMORY_MAP_FAILED;
69 		}
70 		*pBuffer = addr;
71 		return VK_SUCCESS;
72 	}
73 
deallocate(void * buffer,size_t size)74 	void deallocate(void *buffer, size_t size) override
75 	{
76 		memfd.unmap(buffer, size);
77 	}
78 
getFlagBit() const79 	VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
80 	{
81 		return typeFlagBit;
82 	}
83 
exportFd(int * pFd) const84 	VkResult exportFd(int *pFd) const override
85 	{
86 		int fd = memfd.exportFd();
87 		if(fd < 0)
88 		{
89 			return VK_ERROR_INVALID_EXTERNAL_HANDLE;
90 		}
91 		*pFd = fd;
92 		return VK_SUCCESS;
93 	}
94 
95 private:
96 	LinuxMemFd memfd;
97 	OpaqueFdAllocateInfo allocateInfo;
98 };
99