xref: /aosp_15_r20/external/swiftshader/src/Vulkan/VkDeviceMemoryExternalMac.hpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
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