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 "VkDebug.hpp" |
16 | #include "System/Linux/MemFd.hpp" |
17 | |
18 | #include <errno.h> |
19 | #include <string.h> |
20 | #include <sys/mman.h> |
21 | |
22 | class LinuxMemfdExternalMemory : public vk::DeviceMemory::ExternalBase |
23 | { |
24 | public: |
25 | // Helper struct to parse the VkMemoryAllocateInfo.pNext chain and |
26 | // extract relevant information related to the handle type supported |
27 | // by this DeviceMemory;:ExternalBase subclass. |
28 | struct AllocateInfo |
29 | { |
30 | bool importFd = false; |
31 | bool exportFd = false; |
32 | int fd = -1; |
33 | |
34 | AllocateInfo() = default; |
35 | |
36 | // Parse the VkMemoryAllocateInfo.pNext chain to initialize an AllocateInfo. |
37 | AllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo) |
38 | { |
39 | const auto* createInfo = reinterpret_cast<const VkBaseInStructure*>(pAllocateInfo->pNext); |
40 | while (createInfo) |
41 | { |
42 | switch (createInfo->sType) |
43 | { |
44 | case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: |
45 | { |
46 | const auto* importInfo = reinterpret_cast<const VkImportMemoryFdInfoKHR*>(createInfo); |
47 | |
48 | if (importInfo->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) |
49 | { |
50 | UNIMPLEMENTED("importInfo->handleType" ); |
51 | } |
52 | importFd = true; |
53 | fd = importInfo->fd; |
54 | } |
55 | break; |
56 | case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: |
57 | { |
58 | const auto* exportInfo = reinterpret_cast<const VkExportMemoryAllocateInfo*>(createInfo); |
59 | |
60 | if (exportInfo->handleTypes != VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) |
61 | { |
62 | UNIMPLEMENTED("exportInfo->handleTypes" ); |
63 | } |
64 | exportFd = true; |
65 | } |
66 | break; |
67 | |
68 | default: |
69 | ; |
70 | } |
71 | createInfo = createInfo->pNext; |
72 | } |
73 | } |
74 | }; |
75 | |
76 | static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; |
77 | |
78 | static bool supportsAllocateInfo(const VkMemoryAllocateInfo* pAllocateInfo) |
79 | { |
80 | AllocateInfo info(pAllocateInfo); |
81 | return info.importFd || info.exportFd; |
82 | } |
83 | |
84 | explicit LinuxMemfdExternalMemory(const VkMemoryAllocateInfo* pAllocateInfo) |
85 | : allocateInfo(pAllocateInfo) |
86 | { |
87 | } |
88 | |
89 | ~LinuxMemfdExternalMemory() |
90 | { |
91 | memfd.close(); |
92 | } |
93 | |
94 | VkResult allocate(size_t size, void** pBuffer) override |
95 | { |
96 | if (allocateInfo.importFd) |
97 | { |
98 | memfd.importFd(allocateInfo.fd); |
99 | if (!memfd.isValid()) |
100 | { |
101 | return VK_ERROR_INVALID_EXTERNAL_HANDLE; |
102 | } |
103 | } |
104 | else |
105 | { |
106 | ASSERT(allocateInfo.exportFd); |
107 | static int counter = 0; |
108 | char name[40]; |
109 | snprintf(name, sizeof(name), "SwiftShader.Memory.%d" , ++counter); |
110 | if (!memfd.allocate(name, size)) |
111 | { |
112 | TRACE("memfd.allocate() returned %s" , strerror(errno)); |
113 | return VK_ERROR_OUT_OF_DEVICE_MEMORY; |
114 | } |
115 | } |
116 | void* addr = memfd.mapReadWrite(0, size); |
117 | if (!addr) |
118 | { |
119 | return VK_ERROR_MEMORY_MAP_FAILED; |
120 | } |
121 | *pBuffer = addr; |
122 | return VK_SUCCESS; |
123 | } |
124 | |
125 | void deallocate(void* buffer, size_t size) override |
126 | { |
127 | memfd.unmap(buffer, size); |
128 | } |
129 | |
130 | VkExternalMemoryHandleTypeFlagBits getFlagBit() const override |
131 | { |
132 | return typeFlagBit; |
133 | } |
134 | |
135 | VkResult exportFd(int* pFd) const override |
136 | { |
137 | int fd = memfd.exportFd(); |
138 | if (fd < 0) |
139 | { |
140 | return VK_ERROR_INVALID_EXTERNAL_HANDLE; |
141 | } |
142 | *pFd = fd; |
143 | return VK_SUCCESS; |
144 | } |
145 | |
146 | private: |
147 | LinuxMemFd memfd; |
148 | AllocateInfo allocateInfo; |
149 | }; |
150 | |