1*03ce13f7SAndroid Build Coastguard Worker // Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker //
7*03ce13f7SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker //
9*03ce13f7SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker // limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker #include "VkDeviceMemory.hpp"
16*03ce13f7SAndroid Build Coastguard Worker
17*03ce13f7SAndroid Build Coastguard Worker #include "System/Debug.hpp"
18*03ce13f7SAndroid Build Coastguard Worker
19*03ce13f7SAndroid Build Coastguard Worker #include <errno.h>
20*03ce13f7SAndroid Build Coastguard Worker #include <fcntl.h>
21*03ce13f7SAndroid Build Coastguard Worker #include <string.h>
22*03ce13f7SAndroid Build Coastguard Worker #include <sys/mman.h>
23*03ce13f7SAndroid Build Coastguard Worker #include <unistd.h>
24*03ce13f7SAndroid Build Coastguard Worker
25*03ce13f7SAndroid Build Coastguard Worker #ifndef __APPLE__
26*03ce13f7SAndroid Build Coastguard Worker # error "This file is for macOS only!"
27*03ce13f7SAndroid Build Coastguard Worker #endif // __APPLE__
28*03ce13f7SAndroid Build Coastguard Worker
29*03ce13f7SAndroid Build Coastguard Worker #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12
30*03ce13f7SAndroid Build Coastguard Worker # include <mach/mach_time.h>
31*03ce13f7SAndroid Build Coastguard Worker #endif // __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12
32*03ce13f7SAndroid Build Coastguard Worker
33*03ce13f7SAndroid Build Coastguard Worker namespace {
34*03ce13f7SAndroid Build Coastguard Worker
GetTime()35*03ce13f7SAndroid Build Coastguard Worker struct timespec GetTime()
36*03ce13f7SAndroid Build Coastguard Worker {
37*03ce13f7SAndroid Build Coastguard Worker struct timespec tv;
38*03ce13f7SAndroid Build Coastguard Worker
39*03ce13f7SAndroid Build Coastguard Worker #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12
40*03ce13f7SAndroid Build Coastguard Worker clock_gettime(CLOCK_REALTIME, &tv);
41*03ce13f7SAndroid Build Coastguard Worker #else
42*03ce13f7SAndroid Build Coastguard Worker mach_timebase_info_data_t timebase;
43*03ce13f7SAndroid Build Coastguard Worker mach_timebase_info(&timebase);
44*03ce13f7SAndroid Build Coastguard Worker uint64_t time;
45*03ce13f7SAndroid Build Coastguard Worker time = mach_absolute_time();
46*03ce13f7SAndroid Build Coastguard Worker
47*03ce13f7SAndroid Build Coastguard Worker double convert_ratio = (double)timebase.numer / (double)timebase.denom;
48*03ce13f7SAndroid Build Coastguard Worker uint64_t secs = (uint64_t)((double)time * convert_ratio / 1e-9);
49*03ce13f7SAndroid Build Coastguard Worker uint64_t usecs = (uint64_t)((double)time * convert_ratio - secs * 1e9);
50*03ce13f7SAndroid Build Coastguard Worker tv.tv_sec = secs;
51*03ce13f7SAndroid Build Coastguard Worker tv.tv_nsec = usecs;
52*03ce13f7SAndroid Build Coastguard Worker #endif
53*03ce13f7SAndroid Build Coastguard Worker return tv;
54*03ce13f7SAndroid Build Coastguard Worker }
55*03ce13f7SAndroid Build Coastguard Worker
56*03ce13f7SAndroid Build Coastguard Worker } // namespace
57*03ce13f7SAndroid Build Coastguard Worker
58*03ce13f7SAndroid Build Coastguard Worker // An implementation of OpaqueFdExternalMemory that relies on shm_open().
59*03ce13f7SAndroid Build Coastguard Worker // Useful on OS X which do not have Linux memfd regions.
60*03ce13f7SAndroid Build Coastguard Worker class OpaqueFdExternalMemory : public vk::DeviceMemory, public vk::ObjectBase<OpaqueFdExternalMemory, VkDeviceMemory>
61*03ce13f7SAndroid Build Coastguard Worker {
62*03ce13f7SAndroid Build Coastguard Worker public:
63*03ce13f7SAndroid Build Coastguard Worker static const VkExternalMemoryHandleTypeFlagBits typeFlagBit = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
64*03ce13f7SAndroid Build Coastguard Worker
SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo & extendedAllocationInfo)65*03ce13f7SAndroid Build Coastguard Worker static bool SupportsAllocateInfo(const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo)
66*03ce13f7SAndroid Build Coastguard Worker {
67*03ce13f7SAndroid Build Coastguard Worker OpaqueFdAllocateInfo info(extendedAllocationInfo);
68*03ce13f7SAndroid Build Coastguard Worker return info.importFd || info.exportFd;
69*03ce13f7SAndroid Build Coastguard Worker }
70*03ce13f7SAndroid Build Coastguard Worker
OpaqueFdExternalMemory(const VkMemoryAllocateInfo * pCreateInfo,void * mem,const vk::DeviceMemory::ExtendedAllocationInfo & extendedAllocationInfo,vk::Device * pDevice)71*03ce13f7SAndroid Build Coastguard Worker explicit OpaqueFdExternalMemory(const VkMemoryAllocateInfo *pCreateInfo, void *mem, const vk::DeviceMemory::ExtendedAllocationInfo &extendedAllocationInfo, vk::Device *pDevice)
72*03ce13f7SAndroid Build Coastguard Worker : vk::DeviceMemory(pCreateInfo, extendedAllocationInfo, pDevice)
73*03ce13f7SAndroid Build Coastguard Worker , allocateInfo(extendedAllocationInfo)
74*03ce13f7SAndroid Build Coastguard Worker {
75*03ce13f7SAndroid Build Coastguard Worker }
76*03ce13f7SAndroid Build Coastguard Worker
~OpaqueFdExternalMemory()77*03ce13f7SAndroid Build Coastguard Worker ~OpaqueFdExternalMemory()
78*03ce13f7SAndroid Build Coastguard Worker {
79*03ce13f7SAndroid Build Coastguard Worker if(shm_fd_ >= 0)
80*03ce13f7SAndroid Build Coastguard Worker {
81*03ce13f7SAndroid Build Coastguard Worker ::close(shm_fd_);
82*03ce13f7SAndroid Build Coastguard Worker shm_fd_ = -1;
83*03ce13f7SAndroid Build Coastguard Worker }
84*03ce13f7SAndroid Build Coastguard Worker }
85*03ce13f7SAndroid Build Coastguard Worker
allocateBuffer()86*03ce13f7SAndroid Build Coastguard Worker VkResult allocateBuffer() override
87*03ce13f7SAndroid Build Coastguard Worker {
88*03ce13f7SAndroid Build Coastguard Worker if(allocateInfo.importFd)
89*03ce13f7SAndroid Build Coastguard Worker {
90*03ce13f7SAndroid Build Coastguard Worker shm_fd_ = allocateInfo.fd;
91*03ce13f7SAndroid Build Coastguard Worker if(shm_fd_ < 0)
92*03ce13f7SAndroid Build Coastguard Worker {
93*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INVALID_EXTERNAL_HANDLE;
94*03ce13f7SAndroid Build Coastguard Worker }
95*03ce13f7SAndroid Build Coastguard Worker }
96*03ce13f7SAndroid Build Coastguard Worker else
97*03ce13f7SAndroid Build Coastguard Worker {
98*03ce13f7SAndroid Build Coastguard Worker ASSERT(allocateInfo.exportFd);
99*03ce13f7SAndroid Build Coastguard Worker // Create shared memory region with shm_open() and a randomly-generated region name.
100*03ce13f7SAndroid Build Coastguard Worker static const char kPrefix[] = "/SwiftShader-";
101*03ce13f7SAndroid Build Coastguard Worker const size_t kPrefixSize = sizeof(kPrefix) - 1;
102*03ce13f7SAndroid Build Coastguard Worker const size_t kRandomSize = 8;
103*03ce13f7SAndroid Build Coastguard Worker
104*03ce13f7SAndroid Build Coastguard Worker char name[kPrefixSize + kRandomSize + 1u];
105*03ce13f7SAndroid Build Coastguard Worker memcpy(name, kPrefix, kPrefixSize);
106*03ce13f7SAndroid Build Coastguard Worker
107*03ce13f7SAndroid Build Coastguard Worker int fd = -1;
108*03ce13f7SAndroid Build Coastguard Worker for(int tries = 0; tries < 6; ++tries)
109*03ce13f7SAndroid Build Coastguard Worker {
110*03ce13f7SAndroid Build Coastguard Worker struct timespec tv = GetTime();
111*03ce13f7SAndroid Build Coastguard Worker uint64_t r = (uint64_t)tv.tv_sec + (uint64_t)tv.tv_nsec;
112*03ce13f7SAndroid Build Coastguard Worker for(size_t pos = 0; pos < kRandomSize; ++pos, r /= 8)
113*03ce13f7SAndroid Build Coastguard Worker {
114*03ce13f7SAndroid Build Coastguard Worker name[kPrefixSize + pos] = '0' + (r % 8);
115*03ce13f7SAndroid Build Coastguard Worker }
116*03ce13f7SAndroid Build Coastguard Worker name[kPrefixSize + kRandomSize] = '\0';
117*03ce13f7SAndroid Build Coastguard Worker
118*03ce13f7SAndroid Build Coastguard Worker fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
119*03ce13f7SAndroid Build Coastguard Worker if(fd >= 0)
120*03ce13f7SAndroid Build Coastguard Worker break;
121*03ce13f7SAndroid Build Coastguard Worker
122*03ce13f7SAndroid Build Coastguard Worker if(errno != EEXIST)
123*03ce13f7SAndroid Build Coastguard Worker {
124*03ce13f7SAndroid Build Coastguard Worker TRACE("shm_open() failed with: %s", strerror(errno));
125*03ce13f7SAndroid Build Coastguard Worker break;
126*03ce13f7SAndroid Build Coastguard Worker }
127*03ce13f7SAndroid Build Coastguard Worker }
128*03ce13f7SAndroid Build Coastguard Worker
129*03ce13f7SAndroid Build Coastguard Worker // Unlink the name since it's not needed anymore.
130*03ce13f7SAndroid Build Coastguard Worker if(fd >= 0)
131*03ce13f7SAndroid Build Coastguard Worker {
132*03ce13f7SAndroid Build Coastguard Worker if(shm_unlink(name) == -1)
133*03ce13f7SAndroid Build Coastguard Worker {
134*03ce13f7SAndroid Build Coastguard Worker TRACE("shm_unlink() failed with: %s", strerror(errno));
135*03ce13f7SAndroid Build Coastguard Worker close(fd);
136*03ce13f7SAndroid Build Coastguard Worker fd = -1;
137*03ce13f7SAndroid Build Coastguard Worker }
138*03ce13f7SAndroid Build Coastguard Worker }
139*03ce13f7SAndroid Build Coastguard Worker
140*03ce13f7SAndroid Build Coastguard Worker // Ensure there is enough space.
141*03ce13f7SAndroid Build Coastguard Worker if(fd >= 0 && allocationSize > 0)
142*03ce13f7SAndroid Build Coastguard Worker {
143*03ce13f7SAndroid Build Coastguard Worker if(::ftruncate(fd, allocationSize) < 0)
144*03ce13f7SAndroid Build Coastguard Worker {
145*03ce13f7SAndroid Build Coastguard Worker TRACE("ftruncate() failed with: %s", strerror(errno));
146*03ce13f7SAndroid Build Coastguard Worker close(fd);
147*03ce13f7SAndroid Build Coastguard Worker fd = -1;
148*03ce13f7SAndroid Build Coastguard Worker }
149*03ce13f7SAndroid Build Coastguard Worker }
150*03ce13f7SAndroid Build Coastguard Worker
151*03ce13f7SAndroid Build Coastguard Worker if(fd < 0)
152*03ce13f7SAndroid Build Coastguard Worker {
153*03ce13f7SAndroid Build Coastguard Worker TRACE("Could not allocate shared memory region");
154*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_OUT_OF_DEVICE_MEMORY;
155*03ce13f7SAndroid Build Coastguard Worker }
156*03ce13f7SAndroid Build Coastguard Worker
157*03ce13f7SAndroid Build Coastguard Worker shm_fd_ = fd;
158*03ce13f7SAndroid Build Coastguard Worker }
159*03ce13f7SAndroid Build Coastguard Worker
160*03ce13f7SAndroid Build Coastguard Worker void *addr = ::mmap(nullptr, allocationSize, PROT_READ | PROT_WRITE, MAP_SHARED,
161*03ce13f7SAndroid Build Coastguard Worker shm_fd_, 0);
162*03ce13f7SAndroid Build Coastguard Worker
163*03ce13f7SAndroid Build Coastguard Worker if(addr == MAP_FAILED)
164*03ce13f7SAndroid Build Coastguard Worker {
165*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_MEMORY_MAP_FAILED;
166*03ce13f7SAndroid Build Coastguard Worker }
167*03ce13f7SAndroid Build Coastguard Worker buffer = addr;
168*03ce13f7SAndroid Build Coastguard Worker return VK_SUCCESS;
169*03ce13f7SAndroid Build Coastguard Worker }
170*03ce13f7SAndroid Build Coastguard Worker
freeBuffer()171*03ce13f7SAndroid Build Coastguard Worker void freeBuffer() override
172*03ce13f7SAndroid Build Coastguard Worker {
173*03ce13f7SAndroid Build Coastguard Worker ::munmap(buffer, allocationSize);
174*03ce13f7SAndroid Build Coastguard Worker }
175*03ce13f7SAndroid Build Coastguard Worker
getFlagBit() const176*03ce13f7SAndroid Build Coastguard Worker VkExternalMemoryHandleTypeFlagBits getFlagBit() const override
177*03ce13f7SAndroid Build Coastguard Worker {
178*03ce13f7SAndroid Build Coastguard Worker return typeFlagBit;
179*03ce13f7SAndroid Build Coastguard Worker }
180*03ce13f7SAndroid Build Coastguard Worker
exportFd(int * pFd) const181*03ce13f7SAndroid Build Coastguard Worker VkResult exportFd(int *pFd) const override
182*03ce13f7SAndroid Build Coastguard Worker {
183*03ce13f7SAndroid Build Coastguard Worker int fd = dup(shm_fd_);
184*03ce13f7SAndroid Build Coastguard Worker if(fd < 0)
185*03ce13f7SAndroid Build Coastguard Worker {
186*03ce13f7SAndroid Build Coastguard Worker return VK_ERROR_INVALID_EXTERNAL_HANDLE;
187*03ce13f7SAndroid Build Coastguard Worker }
188*03ce13f7SAndroid Build Coastguard Worker
189*03ce13f7SAndroid Build Coastguard Worker // Set the clo-on-exec flag.
190*03ce13f7SAndroid Build Coastguard Worker int flags = ::fcntl(fd, F_GETFD);
191*03ce13f7SAndroid Build Coastguard Worker ::fcntl(fd, F_SETFL, flags | FD_CLOEXEC);
192*03ce13f7SAndroid Build Coastguard Worker
193*03ce13f7SAndroid Build Coastguard Worker *pFd = fd;
194*03ce13f7SAndroid Build Coastguard Worker return VK_SUCCESS;
195*03ce13f7SAndroid Build Coastguard Worker }
196*03ce13f7SAndroid Build Coastguard Worker
197*03ce13f7SAndroid Build Coastguard Worker private:
198*03ce13f7SAndroid Build Coastguard Worker int shm_fd_ = -1;
199*03ce13f7SAndroid Build Coastguard Worker OpaqueFdAllocateInfo allocateInfo;
200*03ce13f7SAndroid Build Coastguard Worker };
201