Line data Source code
1 : /**
2 : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "XLVkSync.h"
25 : #include "XLVkDevice.h"
26 :
27 : #ifndef XL_VKAPI_LOG
28 : #define XL_VKAPI_LOG(...)
29 : #endif
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
32 :
33 268748 : Semaphore::~Semaphore() { }
34 :
35 134374 : static void Semaphore_destroy(core::Device *dev, core::ObjectType, core::ObjectHandle ptr, void *) {
36 134374 : auto d = ((Device *)dev);
37 134374 : d->getTable()->vkDestroySemaphore(d->getDevice(), (VkSemaphore)ptr.get(), nullptr);
38 134374 : }
39 :
40 146 : static void Fence_destroy(core::Device *dev, core::ObjectType, core::ObjectHandle ptr, void *) {
41 146 : auto d = ((Device *)dev);
42 146 : d->getTable()->vkDestroyFence(d->getDevice(), (VkFence)ptr.get(), nullptr);
43 146 : }
44 :
45 134374 : bool Semaphore::init(Device &dev) {
46 134374 : VkSemaphoreCreateInfo semaphoreInfo{};
47 134374 : semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
48 134374 : semaphoreInfo.pNext = nullptr;
49 134374 : semaphoreInfo.flags = 0;
50 :
51 134374 : if (dev.getTable()->vkCreateSemaphore(dev.getDevice(), &semaphoreInfo, nullptr, &_sem) == VK_SUCCESS) {
52 134374 : return core::Semaphore::init(dev, Semaphore_destroy, core::ObjectType::Semaphore, core::ObjectHandle(_sem));
53 : }
54 :
55 0 : return false;
56 : }
57 :
58 292 : Fence::~Fence() {
59 146 : doRelease(false);
60 292 : }
61 :
62 146 : bool Fence::init(Device &dev) {
63 146 : VkFenceCreateInfo fenceInfo{};
64 146 : fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
65 146 : fenceInfo.pNext = nullptr;
66 146 : fenceInfo.flags = 0;
67 :
68 146 : _state = Disabled;
69 :
70 146 : if (dev.getTable()->vkCreateFence(dev.getDevice(), &fenceInfo, nullptr, &_fence) == VK_SUCCESS) {
71 146 : return core::Object::init(dev, Fence_destroy, core::ObjectType::Fence, core::ObjectHandle(_fence));
72 : }
73 0 : return false;
74 : }
75 :
76 207399 : void Fence::clear() {
77 207399 : if (_releaseFn) {
78 0 : _releaseFn = nullptr;
79 : }
80 207399 : if (_scheduleFn) {
81 9517 : _scheduleFn = nullptr;
82 : }
83 207399 : }
84 :
85 207399 : void Fence::setFrame(Function<bool()> &&schedule, Function<void()> &&release, uint64_t f) {
86 207399 : _frame = f;
87 207399 : _scheduleFn = move(schedule);
88 207399 : _releaseFn = move(release);
89 207399 : }
90 :
91 0 : void Fence::setScheduleCallback(Function<bool()> &&schedule) {
92 0 : _scheduleFn = move(schedule);
93 0 : }
94 :
95 0 : void Fence::setReleaseCallback(Function<bool()> &&release) {
96 0 : _releaseFn = move(release);
97 0 : }
98 :
99 197902 : void Fence::setArmed(DeviceQueue &q) {
100 197902 : std::unique_lock<Mutex> lock(_mutex);
101 197901 : _state = Armed;
102 197901 : _queue = &q;
103 197901 : _queue->retainFence(*this);
104 197902 : _armedTime = platform::clock(core::ClockType::Monotonic);
105 197900 : }
106 :
107 9538 : void Fence::setArmed() {
108 9538 : std::unique_lock<Mutex> lock(_mutex);
109 9538 : _state = Armed;
110 9538 : _armedTime = platform::clock(core::ClockType::Monotonic);
111 9538 : }
112 :
113 182115 : void Fence::setTag(StringView tag) {
114 182115 : _tag = tag;
115 182115 : }
116 :
117 534485 : void Fence::addRelease(Function<void(bool)> &&cb, Ref *ref, StringView tag) {
118 534485 : std::unique_lock<Mutex> lock(_mutex);
119 534485 : _release.emplace_back(ReleaseHandle({move(cb), ref, tag}));
120 534485 : }
121 :
122 197882 : bool Fence::schedule(Loop &loop) {
123 197882 : std::unique_lock<Mutex> lock(_mutex);
124 197882 : if (_state != Armed) {
125 0 : lock.unlock();
126 0 : if (_releaseFn) {
127 0 : loop.performOnGlThread([this] {
128 0 : doRelease(false);
129 :
130 0 : if (_releaseFn) {
131 0 : auto releaseFn = move(_releaseFn);
132 0 : _releaseFn = nullptr;
133 0 : _scheduleFn = nullptr;
134 0 : releaseFn();
135 0 : } else {
136 0 : _scheduleFn = nullptr;
137 : }
138 0 : }, this, true);
139 : } else {
140 0 : doRelease(false);
141 0 : _scheduleFn = nullptr;
142 : }
143 0 : return false;
144 : } else {
145 197882 : lock.unlock();
146 :
147 197882 : if (check(loop, true)) {
148 96672 : _scheduleFn = nullptr;
149 96672 : return false;
150 : }
151 : }
152 :
153 101210 : if (!_scheduleFn) {
154 0 : return false;
155 : }
156 :
157 101210 : auto scheduleFn = move(_scheduleFn);
158 101210 : _scheduleFn = nullptr;
159 :
160 101210 : if (lock.owns_lock()) {
161 0 : lock.unlock();
162 : }
163 :
164 101210 : return scheduleFn();
165 197882 : }
166 :
167 107271349 : bool Fence::check(Loop &loop, bool lockfree) {
168 107271349 : std::unique_lock<Mutex> lock(_mutex);
169 107271346 : if (_state != Armed) {
170 0 : return true;
171 : }
172 :
173 107271346 : auto dev = ((Device *)_object.device);
174 : enum VkResult status;
175 :
176 107271346 : dev->makeApiCall([&, this] (const DeviceTable &table, VkDevice device) {
177 107271321 : if (lockfree) {
178 107261865 : status = table.vkGetFenceStatus(device, _fence);
179 : } else {
180 9456 : status = table.vkWaitForFences(device, 1, &_fence, VK_TRUE, UINT64_MAX);
181 : }
182 107271424 : });
183 :
184 107271406 : switch (status) {
185 207440 : case VK_SUCCESS:
186 207440 : _state = Signaled;
187 : XL_VKAPI_LOG("Fence [", _frame, "] ", _tag, ": signaled: ", platform::clock(core::ClockType::Monotonic) - _armedTime);
188 207440 : lock.unlock();
189 207439 : if (loop.isOnGlThread()) {
190 197882 : doRelease(true);
191 197882 : scheduleReset(loop);
192 : } else {
193 9558 : scheduleReleaseReset(loop, true);
194 : }
195 207441 : return true;
196 : break;
197 107063983 : case VK_TIMEOUT:
198 : case VK_NOT_READY:
199 107063983 : _state = Armed;
200 107063983 : if (platform::clock(core::ClockType::Monotonic) - _armedTime > 1'000'000) {
201 0 : lock.unlock();
202 0 : if (_queue) {
203 : XL_VKAPI_LOG("Fence [", _queue->getFrameIndex(), "] Fence is possibly broken: ", _tag);
204 : } else {
205 : XL_VKAPI_LOG("Fence [", _frame, "] Fence is possibly broken: ", _tag);
206 : }
207 0 : return check(loop, false);
208 : }
209 107063983 : return false;
210 0 : default:
211 0 : break;
212 : }
213 0 : return false;
214 107271407 : }
215 :
216 328136 : void Fence::autorelease(Rc<Ref> &&ref) {
217 328136 : _autorelease.emplace_back(move(ref));
218 328136 : }
219 :
220 197882 : void Fence::scheduleReset(Loop &loop) {
221 197882 : if (_releaseFn) {
222 197882 : loop.performInQueue(Rc<thread::Task>::create([this] (const thread::Task &) {
223 197882 : auto dev = ((Device *)_object.device);
224 197882 : dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
225 197882 : return true;
226 395764 : }, [this] (const thread::Task &, bool success) {
227 197882 : auto releaseFn = move(_releaseFn);
228 197882 : _releaseFn = nullptr;
229 197882 : releaseFn();
230 593646 : }, this));
231 : } else {
232 0 : auto dev = ((Device *)_object.device);
233 0 : dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
234 : }
235 197882 : }
236 :
237 9559 : void Fence::scheduleReleaseReset(Loop &loop, bool s) {
238 9559 : if (_releaseFn) {
239 9517 : loop.performInQueue(Rc<thread::Task>::create([this] (const thread::Task &) {
240 9517 : auto dev = ((Device *)_object.device);
241 9517 : dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
242 9517 : return true;
243 28551 : }, [this, s] (const thread::Task &, bool success) {
244 9517 : doRelease(s);
245 :
246 9517 : auto releaseFn = move(_releaseFn);
247 9517 : _releaseFn = nullptr;
248 9517 : releaseFn();
249 28551 : }, this));
250 : } else {
251 42 : auto dev = ((Device *)_object.device);
252 42 : dev->getTable()->vkResetFences(dev->getDevice(), 1, &_fence);
253 42 : doRelease(s);
254 : }
255 9559 : }
256 :
257 207587 : void Fence::doRelease(bool success) {
258 207587 : if (_queue) {
259 197903 : _queue->releaseFence(*this);
260 197903 : _queue = nullptr;
261 : }
262 207587 : if (!_release.empty()) {
263 : XL_PROFILE_BEGIN(total, "vk::Fence::reset", "total", 250);
264 732388 : for (auto &it : _release) {
265 534485 : if (it.callback) {
266 : XL_PROFILE_BEGIN(fence, "vk::Fence::reset", it.tag, 250);
267 534485 : it.callback(success);
268 : XL_PROFILE_END(fence);
269 : }
270 : }
271 : XL_PROFILE_END(total);
272 197903 : _release.clear();
273 : }
274 207587 : _autorelease.clear();
275 207587 : _tag = StringView();
276 207587 : }
277 :
278 : }
|