blob: aab89e238655a6d6241ba70aef774e761dea400f [file] [log] [blame]
Alexis Hetu1f23d8c2018-10-16 14:40:19 -04001// Copyright 2018 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#ifndef VK_SEMAPHORE_HPP_
16#define VK_SEMAPHORE_HPP_
17
Antonio Maiorano42fd1592020-04-27 11:30:40 -040018#include "VkConfig.hpp"
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040019#include "VkObject.hpp"
20
David 'Digit' Turner0acac462019-12-10 15:30:22 +010021#include "marl/event.h"
Ben Clayton377573c2020-04-03 20:36:40 +010022#include "marl/mutex.h"
23#include "marl/tsa.h"
David 'Digit' Turner43e33162019-11-22 14:18:49 +010024
Sean Risser68463892020-12-14 16:35:57 -050025#include "System/Synchronization.hpp"
26
David 'Digit' Turner3a7101b2019-11-22 11:55:53 +010027#if VK_USE_PLATFORM_FUCHSIA
Ben Clayton2ed93ab2019-12-17 20:38:03 +000028# include <zircon/types.h>
David 'Digit' Turnerfda994c2019-09-04 16:36:36 +020029#endif
30
Nicolas Capens157ba262019-12-10 17:49:14 -050031namespace vk {
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040032
Sean Risser68463892020-12-14 16:35:57 -050033class BinarySemaphore;
34class TimelineSemaphore;
35
36class Semaphore
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040037{
38public:
Sean Risser68463892020-12-14 16:35:57 -050039 Semaphore(VkSemaphoreType type);
40
41 virtual ~Semaphore() = default;
42
43 static inline Semaphore *Cast(VkSemaphore semaphore)
44 {
45 return static_cast<Semaphore *>(static_cast<void *>(semaphore));
46 }
47
48 virtual void destroy(const VkAllocationCallbacks *pAllocator)
49 {
50 }
51
52 VkSemaphoreType getSemaphoreType() const;
Sean Risser08762e32021-05-05 14:28:24 -040053 // static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo);
Sean Risser68463892020-12-14 16:35:57 -050054
55protected:
56 VkSemaphoreType type;
57 marl::mutex mutex;
58};
59
60class BinarySemaphore : public Semaphore, public Object<BinarySemaphore, VkSemaphore>
61{
62public:
63 BinarySemaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const VkAllocationCallbacks *pAllocator);
Ben Clayton2ed93ab2019-12-17 20:38:03 +000064 void destroy(const VkAllocationCallbacks *pAllocator);
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040065
Ben Clayton2ed93ab2019-12-17 20:38:03 +000066 static size_t ComputeRequiredAllocationSize(const VkSemaphoreCreateInfo *pCreateInfo);
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040067
David 'Digit' Turner99938ea2019-09-03 15:11:17 +020068 void wait();
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040069
Ben Clayton2ed93ab2019-12-17 20:38:03 +000070 void wait(const VkPipelineStageFlags &flag)
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040071 {
David 'Digit' Turner99938ea2019-09-03 15:11:17 +020072 // NOTE: not sure what else to do here?
73 wait();
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040074 }
75
David 'Digit' Turner99938ea2019-09-03 15:11:17 +020076 void signal();
Alexis Hetu1f23d8c2018-10-16 14:40:19 -040077
David 'Digit' Turner3a7101b2019-11-22 11:55:53 +010078#if SWIFTSHADER_EXTERNAL_SEMAPHORE_OPAQUE_FD
David 'Digit' Turner7c4d0a02019-09-03 17:00:02 +020079 VkResult importFd(int fd, bool temporaryImport);
David 'Digit' Turner43e33162019-11-22 14:18:49 +010080 VkResult exportFd(int *pFd);
David 'Digit' Turner7c4d0a02019-09-03 17:00:02 +020081#endif
82
David 'Digit' Turner3a7101b2019-11-22 11:55:53 +010083#if VK_USE_PLATFORM_FUCHSIA
David 'Digit' Turnerfda994c2019-09-04 16:36:36 +020084 VkResult importHandle(zx_handle_t handle, bool temporaryImport);
David 'Digit' Turner43e33162019-11-22 14:18:49 +010085 VkResult exportHandle(zx_handle_t *pHandle);
David 'Digit' Turnerfda994c2019-09-04 16:36:36 +020086#endif
87
David 'Digit' Turner7c4d0a02019-09-03 17:00:02 +020088 class External;
David 'Digit' Turner43e33162019-11-22 14:18:49 +010089
90private:
David 'Digit' Turner2aa80df2019-12-04 12:08:39 +010091 // Small technical note on how semaphores are imported/exported with Vulkan:
92 //
93 // - A Vulkan Semaphore objects has a "payload", corresponding to a
94 // simple atomic boolean flag.
95 //
96 // - A Vulkan Semaphore object can be "exported": this creates a
97 // platform-specific handle / descriptor (which can be passed to other
98 // processes), and is linked in some way to the original semaphore's
99 // payload.
100 //
101 // - Similarly, said handle / descriptor can be "imported" into a Vulkan
102 // Semaphore object. By default, that semaphore loses its payload, and
103 // instead uses the one referenced / shared through the descriptor.
104 //
105 // Hence if semaphore A exports its payload through a descriptor that
106 // is later imported into semaphore B, then both A and B will use/share
107 // the same payload (i.e. signal flag), making cross-process
108 // synchronization possible.
109 //
110 // - There are also "temporary imports", where the target semaphore's
111 // payload is not lost, but is simply hidden/stashed. But the next wait()
112 // operation on the same semaphore should remove the temporary import,
113 // and restore the previous payload.
114 //
115 // - There are many handle / descriptor types, which are listed through
116 // the VkExternalSemaphoreHandleTypeFlagBits. A given Vulkan
117 // implementation might support onle one or several at the same time
118 // (e.g. on Linux or Android, it could support both OPAQUE_FD_BIT and
119 // SYNC_FD_BIT, while on Windows, it would be OPAQUE_WIN32_BIT +
120 // OPAQUE_WIN32_KMT_BIT + D3D12_FENCE_BIT).
121 //
122 // - To be able to export a semaphore, VkCreateSemaphore() must be called
123 // with a VkSemaphoreCreateInfo that lists the types of all possible
124 // platform-specific handles the semaphore could be exported to
125 // (e.g. on Linux, it is possible to specify that a semaphore might be
126 // exported as an opaque FD, or as a Linux Sync FD).
127 //
128 // However, which exact type is however only determined later by the
129 // export operation itself (e.g. vkGetSemaphoreFdKHR() could be called to export
130 // either a VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT or a
131 // VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT).
132 //
133 // Once a semaphore has been exported as one type, it is not possible
134 // to export the same payload with a different type (though the spec
135 // doesn't seem to be explicit about this, it's simply impossible in
136 // general).
137 //
138 // This leads to the following design:
139 //
140 // - |internal| is a simple marl::Event that represents the semaphore's
141 // payload when it is not exported, or imported non-temporarily.
142 //
143 // - |external| points to an external semaphore payload. It is created
144 // on demand if the semaphore is exported or imported non-temporarily.
145 // Note that once |external| is created, |internal| is ignored.
146 //
147 // - |tempExternal| points to a linked-list of temporary external
148 // semaphore payloads. The list head corresponds to the most recent
149 // temporary import.
150 //
151
152 // Internal template to allocate a new External implementation.
153 template<class EXTERNAL>
154 External *allocateExternal();
155
156 void deallocateExternal(External *ext);
157
158 // Used internally to import an external payload.
159 // |temporaryImport| is true iff the import is temporary.
160 // |alloc_func| is callable that allocates a new External instance of the
161 // appropriate type.
162 // |import_func| is callable that takes a single parameter, which
163 // corresponds to the external handle/descriptor, and returns a VkResult
164 // values.
165 template<typename ALLOC_FUNC, typename IMPORT_FUNC>
166 VkResult importPayload(bool temporaryImport,
167 ALLOC_FUNC alloc_func,
168 IMPORT_FUNC import_func);
169
170 // Used internally to export a given payload.
171 // |alloc_func| is a callable that allocates a new External instance of
172 // the appropriate type.
173 // |export_func| is a callable that takes a pointer to an External instance,
174 // and a pointer to a handle/descriptor, and returns a VkResult.
175 template<typename ALLOC_FUNC, typename EXPORT_FUNC>
176 VkResult exportPayload(ALLOC_FUNC alloc_func, EXPORT_FUNC export_func);
David 'Digit' Turner43e33162019-11-22 14:18:49 +0100177
178 const VkAllocationCallbacks *allocator = nullptr;
David 'Digit' Turner2aa80df2019-12-04 12:08:39 +0100179 VkExternalSemaphoreHandleTypeFlags exportableHandleTypes = (VkExternalSemaphoreHandleTypeFlags)0;
David 'Digit' Turner2aa80df2019-12-04 12:08:39 +0100180 marl::Event internal;
Ben Clayton377573c2020-04-03 20:36:40 +0100181 External *external GUARDED_BY(mutex) = nullptr;
182 External *tempExternal GUARDED_BY(mutex) = nullptr;
Alexis Hetu1f23d8c2018-10-16 14:40:19 -0400183};
184
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000185static inline Semaphore *Cast(VkSemaphore object)
Alexis Hetu1f23d8c2018-10-16 14:40:19 -0400186{
Alexis Hetubd4cf812019-06-14 15:14:07 -0400187 return Semaphore::Cast(object);
Alexis Hetu1f23d8c2018-10-16 14:40:19 -0400188}
189
Sean Risser68463892020-12-14 16:35:57 -0500190template<typename T>
191static inline T *DynamicCast(VkSemaphore object)
192{
193 Semaphore *semaphore = vk::Cast(object);
194 if(semaphore == nullptr)
195 {
196 return nullptr;
197 }
198
199 static_assert(std::is_same_v<T, BinarySemaphore> || std::is_same_v<T, TimelineSemaphore>);
200 if constexpr(std::is_same_v<T, BinarySemaphore>)
201 {
202 if(semaphore->getSemaphoreType() != VK_SEMAPHORE_TYPE_BINARY)
203 {
204 return nullptr;
205 }
206 }
207 else
208 {
209 if(semaphore->getSemaphoreType() != VK_SEMAPHORE_TYPE_TIMELINE)
210 {
211 return nullptr;
212 }
213 }
214 return static_cast<T *>(semaphore);
215}
216
217// This struct helps parse VkSemaphoreCreateInfo. It also looks at the pNext
218// structures and stores their data flatly in a single struct. The default
219// values of each data member are what the absence of a pNext struct implies
220// for those values.
221struct SemaphoreCreateInfo
222{
223 bool exportSemaphore = false;
224 VkExternalSemaphoreHandleTypeFlags exportHandleTypes = 0;
225
226 VkSemaphoreType semaphoreType = VK_SEMAPHORE_TYPE_BINARY;
227 uint64_t initialPayload = 0;
228
229 SemaphoreCreateInfo(const VkSemaphoreCreateInfo *pCreateInfo);
230};
231
Nicolas Capens157ba262019-12-10 17:49:14 -0500232} // namespace vk
Alexis Hetu1f23d8c2018-10-16 14:40:19 -0400233
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000234#endif // VK_SEMAPHORE_HPP_