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 "VkSemaphore.hpp"
16
17 #include "VkConfig.hpp"
18 #include "VkStringify.hpp"
19
20 #include "marl/blockingcall.h"
21 #include "marl/conditionvariable.h"
22
23 #include <functional>
24 #include <memory>
25 #include <utility>
26
27 namespace vk {
28
29 // This is a base abstract class for all external semaphore implementations
30 // used in this source file.
31 class Semaphore::External
32 {
33 public:
34 virtual ~External() = default;
35
36 // Initialize new instance with a given initial state.
37 virtual VkResult init(bool initialState) = 0;
38
39 virtual bool tryWait() = 0;
40 virtual void wait() = 0;
41 virtual void signal() = 0;
42
43 // For VK_KHR_external_semaphore_fd
importOpaqueFd(int fd)44 virtual VkResult importOpaqueFd(int fd)
45 {
46 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
47 }
48
exportOpaqueFd(int * pFd)49 virtual VkResult exportOpaqueFd(int *pFd)
50 {
51 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
52 }
53
54 #if VK_USE_PLATFORM_FUCHSIA
55 // For VK_FUCHSIA_external_semaphore
importHandle(zx_handle_t handle)56 virtual VkResult importHandle(zx_handle_t handle)
57 {
58 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
59 }
exportHandle(zx_handle_t * pHandle)60 virtual VkResult exportHandle(zx_handle_t *pHandle)
61 {
62 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
63 }
64 #endif
65 // Pointer to previous temporary external instanc,e used for |tempExternal| only.
66 External *previous = nullptr;
67 };
68
69 } // namespace vk
70
71 #if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
72 # if defined(__linux__) || defined(__ANDROID__)
73 # include "VkSemaphoreExternalLinux.hpp"
74 # else
75 # error "Missing VK_KHR_external_semaphore_fd implementation for this platform!"
76 # endif
77 #elif VK_USE_PLATFORM_FUCHSIA
78 # include "VkSemaphoreExternalFuchsia.hpp"
79 #endif
80
81 namespace vk {
82
83 // The bitmask of all external semaphore handle types supported by this source file.
84 static const VkExternalSemaphoreHandleTypeFlags kSupportedTypes =
85 #if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
86 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT |
87 #endif
88 #if VK_USE_PLATFORM_FUCHSIA
89 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA |
90 #endif
91 0;
92
93 namespace {
94
95 struct SemaphoreCreateInfo
96 {
97 bool exportSemaphore = false;
98 VkExternalSemaphoreHandleTypeFlags exportHandleTypes = 0;
99
100 // Create a new instance. The external instance will be allocated only
101 // the pCreateInfo->pNext chain indicates it needs to be exported.
SemaphoreCreateInfovk::__anon0b8af43e0111::SemaphoreCreateInfo102 SemaphoreCreateInfo(const VkSemaphoreCreateInfo *pCreateInfo)
103 {
104 for(const auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
105 nextInfo != nullptr; nextInfo = nextInfo->pNext)
106 {
107 switch(nextInfo->sType)
108 {
109 case VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO:
110 {
111 const auto *exportInfo = reinterpret_cast<const VkExportSemaphoreCreateInfo *>(nextInfo);
112 exportSemaphore = true;
113 exportHandleTypes = exportInfo->handleTypes;
114 if((exportHandleTypes & ~kSupportedTypes) != 0)
115 {
116 UNSUPPORTED("exportInfo->handleTypes 0x%X (supports 0x%X)",
117 int(exportHandleTypes),
118 int(kSupportedTypes));
119 }
120 }
121 break;
122 default:
123 WARN("nextInfo->sType = %s", vk::Stringify(nextInfo->sType).c_str());
124 }
125 }
126 }
127 };
128
129 } // namespace
130
wait()131 void Semaphore::wait()
132 {
133 marl::lock lock(mutex);
134 External *ext = tempExternal ? tempExternal : external;
135 if(ext)
136 {
137 if(!ext->tryWait())
138 {
139 // Dispatch the ext wait to a background thread.
140 // Even if this creates a new thread on each
141 // call, it is assumed that this is negligible
142 // compared with the actual semaphore wait()
143 // operation.
144 lock.unlock_no_tsa();
145 marl::blocking_call([ext]() {
146 ext->wait();
147 });
148 lock.lock_no_tsa();
149 }
150
151 // If the import was temporary, reset the semaphore to its previous state.
152 // See "6.4.5. Importing Semaphore Payloads" in Vulkan 1.1 spec.
153 if(ext == tempExternal)
154 {
155 tempExternal = ext->previous;
156 deallocateExternal(ext);
157 }
158 }
159 else
160 {
161 internal.wait();
162 }
163 }
164
signal()165 void Semaphore::signal()
166 {
167 marl::lock lock(mutex);
168 External *ext = tempExternal ? tempExternal : external;
169 if(ext)
170 {
171 // Assumes that signalling an external semaphore is non-blocking,
172 // so it can be performed directly either from a fiber or thread.
173 ext->signal();
174 }
175 else
176 {
177 internal.signal();
178 }
179 }
180
Semaphore(const VkSemaphoreCreateInfo * pCreateInfo,void * mem,const VkAllocationCallbacks * pAllocator)181 Semaphore::Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator)
182 : allocator(pAllocator)
183 {
184 SemaphoreCreateInfo info(pCreateInfo);
185 exportableHandleTypes = info.exportHandleTypes;
186 }
187
destroy(const VkAllocationCallbacks * pAllocator)188 void Semaphore::destroy(const VkAllocationCallbacks *pAllocator)
189 {
190 marl::lock lock(mutex);
191 while(tempExternal)
192 {
193 External *ext = tempExternal;
194 tempExternal = ext->previous;
195 deallocateExternal(ext);
196 }
197 if(external)
198 {
199 deallocateExternal(external);
200 external = nullptr;
201 }
202 }
203
ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo * pCreateInfo)204 size_t Semaphore::ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo)
205 {
206 // Semaphore::External instance is created and destroyed on demand so return 0 here.
207 return 0;
208 }
209
210 template<class EXTERNAL>
allocateExternal()211 Semaphore::External *Semaphore::allocateExternal()
212 {
213 auto *ext = reinterpret_cast<Semaphore::External *>(
214 vk::allocate(sizeof(EXTERNAL), alignof(EXTERNAL), allocator));
215 new(ext) EXTERNAL();
216 return ext;
217 }
218
deallocateExternal(Semaphore::External * ext)219 void Semaphore::deallocateExternal(Semaphore::External *ext)
220 {
221 ext->~External();
222 vk::deallocate(ext, allocator);
223 }
224
225 template<typename ALLOC_FUNC, typename IMPORT_FUNC>
importPayload(bool temporaryImport,ALLOC_FUNC alloc_func,IMPORT_FUNC import_func)226 VkResult Semaphore::importPayload(bool temporaryImport,
227 ALLOC_FUNC alloc_func,
228 IMPORT_FUNC import_func)
229 {
230 marl::lock lock(mutex);
231
232 // Create new External instance if needed.
233 External *ext = external;
234 if(temporaryImport || !ext)
235 {
236 ext = alloc_func();
237 }
238 VkResult result = import_func(ext);
239 if(result != VK_SUCCESS)
240 {
241 if(temporaryImport || !external)
242 {
243 deallocateExternal(ext);
244 }
245 return result;
246 }
247
248 if(temporaryImport)
249 {
250 ext->previous = tempExternal;
251 tempExternal = ext;
252 }
253 else if(!external)
254 {
255 external = ext;
256 }
257 return VK_SUCCESS;
258 }
259
260 template<typename ALLOC_FUNC, typename EXPORT_FUNC>
exportPayload(ALLOC_FUNC alloc_func,EXPORT_FUNC export_func)261 VkResult Semaphore::exportPayload(ALLOC_FUNC alloc_func, EXPORT_FUNC export_func)
262 {
263 marl::lock lock(mutex);
264 // Sanity check, do not try to export a semaphore that has a temporary import.
265 if(tempExternal != nullptr)
266 {
267 TRACE("Cannot export semaphore with a temporary import!");
268 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
269 }
270 // Allocate |external| if it doesn't exist yet.
271 if(!external)
272 {
273 External *ext = alloc_func();
274 VkResult result = ext->init(internal.isSignalled());
275 if(result != VK_SUCCESS)
276 {
277 deallocateExternal(ext);
278 return result;
279 }
280 external = ext;
281 }
282 return export_func(external);
283 }
284
285 #if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
importFd(int fd,bool temporaryImport)286 VkResult Semaphore::importFd(int fd, bool temporaryImport)
287 {
288 return importPayload(
289 temporaryImport,
290 [this]() {
291 return allocateExternal<OpaqueFdExternalSemaphore>();
292 },
293 [fd](External *ext) {
294 return ext->importOpaqueFd(fd);
295 });
296 }
297
exportFd(int * pFd)298 VkResult Semaphore::exportFd(int *pFd)
299 {
300 if((exportableHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) == 0)
301 {
302 TRACE("Cannot export semaphore as opaque FD (exportableHandleType = 0x%X, want 0x%X)",
303 exportableHandleTypes,
304 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
305
306 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
307 }
308
309 return exportPayload([this]() { return allocateExternal<OpaqueFdExternalSemaphore>(); },
310 [pFd](External *ext) {
311 return ext->exportOpaqueFd(pFd);
312 });
313 }
314 #endif // SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
315
316 #if VK_USE_PLATFORM_FUCHSIA
importHandle(zx_handle_t handle,bool temporaryImport)317 VkResult Semaphore::importHandle(zx_handle_t handle, bool temporaryImport)
318 {
319 return importPayload(
320 temporaryImport,
321 [this]() {
322 return allocateExternal<ZirconEventExternalSemaphore>();
323 },
324 [handle](External *ext) {
325 return ext->importHandle(handle);
326 });
327 }
328
exportHandle(zx_handle_t * pHandle)329 VkResult Semaphore::exportHandle(zx_handle_t *pHandle)
330 {
331 if((exportableHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA) == 0)
332 {
333 TRACE("Cannot export semaphore as Zircon handle (exportableHandleType = 0x%X, want 0x%X)",
334 exportableHandleTypes,
335 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA);
336
337 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
338 }
339
340 return exportPayload([this]() { return allocateExternal<ZirconEventExternalSemaphore>(); },
341 [pHandle](External *ext) {
342 return ext->exportHandle(pHandle);
343 });
344 }
345 #endif // VK_USE_PLATFORM_FUCHSIA
346
347 } // namespace vk
348