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
22class LinuxMemfdExternalMemory : public vk::DeviceMemory::ExternalBase
23{
24public:
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
146private:
147 LinuxMemFd memfd;
148 AllocateInfo allocateInfo;
149};
150