1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "SyncThread.h"
18 
19 #if GFXSTREAM_ENABLE_HOST_GLES
20 #include "OpenGLESDispatch/OpenGLDispatchLoader.h"
21 #endif
22 
23 #include "aemu/base/Metrics.h"
24 #include "aemu/base/system/System.h"
25 #include "aemu/base/threads/Thread.h"
26 #include "host-common/GfxstreamFatalError.h"
27 #include "host-common/crash_reporter.h"
28 #include "host-common/logging.h"
29 #include "host-common/sync_device.h"
30 
31 #ifndef _MSC_VER
32 #include <sys/time.h>
33 #endif
34 #include <memory>
35 
36 namespace gfxstream {
37 
38 using android::base::EventHangMetadata;
39 using emugl::ABORT_REASON_OTHER;
40 using emugl::FatalError;
41 
42 #if GFXSTREAM_ENABLE_HOST_GLES
43 using gl::EGLDispatch;
44 using gl::EmulatedEglFenceSync;
45 #endif
46 
47 #define DEBUG 0
48 
49 #if DEBUG
50 
curr_ms()51 static uint64_t curr_ms() {
52     struct timeval tv;
53     gettimeofday(&tv, NULL);
54     return tv.tv_usec / 1000 + tv.tv_sec * 1000;
55 }
56 
57 #define DPRINT(fmt, ...) do { \
58     if (!VERBOSE_CHECK(syncthreads)) VERBOSE_ENABLE(syncthreads); \
59     VERBOSE_TID_FUNCTION_DPRINT(syncthreads, "@ time=%llu: " fmt, curr_ms(), ##__VA_ARGS__); \
60 } while(0)
61 
62 #else
63 
64 #define DPRINT(...)
65 
66 #endif
67 
68 #define SYNC_THREAD_CHECK(condition)                                        \
69     do {                                                                    \
70         if (!(condition)) {                                                 \
71             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<              \
72                 #condition << " is false";                                  \
73         }                                                                   \
74     } while (0)
75 
76 // The single global sync thread instance.
77 class GlobalSyncThread {
78 public:
79     GlobalSyncThread() = default;
80 
initialize(bool hasGl,HealthMonitor<> * healthMonitor)81     void initialize(bool hasGl, HealthMonitor<>* healthMonitor) {
82         AutoLock mutex(mLock);
83         SYNC_THREAD_CHECK(!mSyncThread);
84         mSyncThread = std::make_unique<SyncThread>(hasGl, healthMonitor);
85     }
syncThreadPtr()86     SyncThread* syncThreadPtr() {
87         AutoLock mutex(mLock);
88         return mSyncThread.get();
89     }
90 
destroy()91     void destroy() {
92         AutoLock mutex(mLock);
93         mSyncThread = nullptr;
94     }
95 
96 private:
97     std::unique_ptr<SyncThread> mSyncThread = nullptr;
98     // lock for the access to this object
99     android::base::Lock mLock;
100     using AutoLock = android::base::AutoLock;
101 };
102 
sGlobalSyncThread()103 static GlobalSyncThread* sGlobalSyncThread() {
104     static GlobalSyncThread* t = new GlobalSyncThread;
105     return t;
106 }
107 
108 static const uint32_t kTimelineInterval = 1;
109 static const uint64_t kDefaultTimeoutNsecs = 5ULL * 1000ULL * 1000ULL * 1000ULL;
110 
SyncThread(bool hasGl,HealthMonitor<> * healthMonitor)111 SyncThread::SyncThread(bool hasGl, HealthMonitor<>* healthMonitor)
112     : android::base::Thread(android::base::ThreadFlags::MaskSignals, 512 * 1024),
113       mWorkerThreadPool(kNumWorkerThreads,
114                         [this](Command&& command, ThreadPool::WorkerId id) {
115                             doSyncThreadCmd(std::move(command), id);
116                         }),
117       mHasGl(hasGl),
118       mHealthMonitor(healthMonitor) {
119     this->start();
120     mWorkerThreadPool.start();
121 #if GFXSTREAM_ENABLE_HOST_GLES
122     if (hasGl) {
123         initSyncEGLContext();
124     }
125 #endif
126 }
127 
~SyncThread()128 SyncThread::~SyncThread() {
129     cleanup();
130 }
131 
132 #if GFXSTREAM_ENABLE_HOST_GLES
triggerWait(EmulatedEglFenceSync * fenceSync,uint64_t timeline)133 void SyncThread::triggerWait(EmulatedEglFenceSync* fenceSync,
134                              uint64_t timeline) {
135     std::stringstream ss;
136     ss << "triggerWait fenceSyncInfo=0x" << std::hex << reinterpret_cast<uintptr_t>(fenceSync)
137        << " timeline=0x" << std::hex << timeline;
138     sendAsync(
139         [fenceSync, timeline, this](WorkerId) {
140             doSyncWait(fenceSync, [timeline] {
141                 DPRINT("wait done (with fence), use goldfish sync timeline inc");
142                 emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
143             });
144         },
145         ss.str());
146 }
147 
triggerBlockedWaitNoTimeline(EmulatedEglFenceSync * fenceSync)148 void SyncThread::triggerBlockedWaitNoTimeline(EmulatedEglFenceSync* fenceSync) {
149     std::stringstream ss;
150     ss << "triggerBlockedWaitNoTimeline fenceSyncInfo=0x" << std::hex
151        << reinterpret_cast<uintptr_t>(fenceSync);
152     sendAndWaitForResult(
153         [fenceSync, this](WorkerId) {
154             doSyncWait(fenceSync, std::function<void()>());
155             return 0;
156         },
157         ss.str());
158 }
159 
triggerWaitWithCompletionCallback(EmulatedEglFenceSync * fenceSync,FenceCompletionCallback cb)160 void SyncThread::triggerWaitWithCompletionCallback(EmulatedEglFenceSync* fenceSync, FenceCompletionCallback cb) {
161     std::stringstream ss;
162     ss << "triggerWaitWithCompletionCallback fenceSyncInfo=0x" << std::hex
163        << reinterpret_cast<uintptr_t>(fenceSync);
164     sendAsync(
165         [fenceSync, cb = std::move(cb), this](WorkerId) { doSyncWait(fenceSync, std::move(cb)); },
166         ss.str());
167 }
168 
initSyncEGLContext()169 void SyncThread::initSyncEGLContext() {
170     mWorkerThreadPool.broadcast([this] {
171         return Command{
172             .mTask = std::packaged_task<int(WorkerId)>([this](WorkerId workerId) {
173                 DPRINT("for worker id: %d", workerId);
174                 // We shouldn't initialize EGL context, when SyncThread is initialized
175                 // without GL enabled.
176                 SYNC_THREAD_CHECK(mHasGl);
177 
178                 const EGLDispatch* egl = gl::LazyLoadedEGLDispatch::get();
179 
180                 mDisplay = egl->eglGetDisplay(EGL_DEFAULT_DISPLAY);
181                 int eglMaj, eglMin;
182                 egl->eglInitialize(mDisplay, &eglMaj, &eglMin);
183 
184                 const EGLint configAttribs[] = {
185                     EGL_SURFACE_TYPE,
186                     EGL_PBUFFER_BIT,
187                     EGL_RENDERABLE_TYPE,
188                     EGL_OPENGL_ES2_BIT,
189                     EGL_RED_SIZE,
190                     8,
191                     EGL_GREEN_SIZE,
192                     8,
193                     EGL_BLUE_SIZE,
194                     8,
195                     EGL_NONE,
196                 };
197 
198                 EGLint nConfigs;
199                 EGLConfig config;
200 
201                 egl->eglChooseConfig(mDisplay, configAttribs, &config, 1, &nConfigs);
202 
203                 const EGLint pbufferAttribs[] = {
204                     EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
205                 };
206 
207                 mSurface[workerId] = egl->eglCreatePbufferSurface(mDisplay, config, pbufferAttribs);
208 
209                 const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
210                 mContext[workerId] =
211                     egl->eglCreateContext(mDisplay, config, EGL_NO_CONTEXT, contextAttribs);
212 
213                 egl->eglMakeCurrent(mDisplay, mSurface[workerId], mSurface[workerId],
214                                     mContext[workerId]);
215                 return 0;
216             }),
217             .mDescription = "init sync EGL context",
218         };
219     });
220     mWorkerThreadPool.waitAllItems();
221 }
222 
doSyncWait(EmulatedEglFenceSync * fenceSync,std::function<void ()> onComplete)223 void SyncThread::doSyncWait(EmulatedEglFenceSync* fenceSync, std::function<void()> onComplete) {
224     DPRINT("enter");
225 
226     if (!EmulatedEglFenceSync::getFromHandle((uint64_t)(uintptr_t)fenceSync)) {
227         if (onComplete) {
228             onComplete();
229         }
230         return;
231     }
232     // We shouldn't use EmulatedEglFenceSync to wait, when SyncThread is initialized
233     // without GL enabled, because EmulatedEglFenceSync uses EGL/GLES.
234     SYNC_THREAD_CHECK(mHasGl);
235 
236     EGLint wait_result = 0x0;
237 
238     DPRINT("wait on sync obj: %p", fenceSync);
239     wait_result = fenceSync->wait(kDefaultTimeoutNsecs);
240 
241     DPRINT(
242         "done waiting, with wait result=0x%x. "
243         "increment timeline (and signal fence)",
244         wait_result);
245 
246     if (wait_result != EGL_CONDITION_SATISFIED_KHR) {
247         EGLint error = gl::s_egl.eglGetError();
248         DPRINT("error: eglClientWaitSync abnormal exit 0x%x. sync handle 0x%llx. egl error = %#x\n",
249                wait_result, (unsigned long long)fenceSync, error);
250         (void)error;
251     }
252 
253     DPRINT("issue timeline increment");
254 
255     // We always unconditionally increment timeline at this point, even
256     // if the call to eglClientWaitSync returned abnormally.
257     // There are three cases to consider:
258     // - EGL_CONDITION_SATISFIED_KHR: either the sync object is already
259     //   signaled and we need to increment this timeline immediately, or
260     //   we have waited until the object is signaled, and then
261     //   we increment the timeline.
262     // - EGL_TIMEOUT_EXPIRED_KHR: the fence command we put in earlier
263     //   in the OpenGL stream is not actually ever signaled, and we
264     //   end up blocking in the above eglClientWaitSyncKHR call until
265     //   our timeout runs out. In this case, provided we have waited
266     //   for |kDefaultTimeoutNsecs|, the guest will have received all
267     //   relevant error messages about fence fd's not being signaled
268     //   in time, so we are properly emulating bad behavior even if
269     //   we now increment the timeline.
270     // - EGL_FALSE (error): chances are, the underlying EGL implementation
271     //   on the host doesn't actually support fence objects. In this case,
272     //   we should fail safe: 1) It must be only very old or faulty
273     //   graphics drivers / GPU's that don't support fence objects.
274     //   2) The consequences of signaling too early are generally, out of
275     //   order frames and scrambled textures in some apps. But, not
276     //   incrementing the timeline means that the app's rendering freezes.
277     //   So, despite the faulty GPU driver, not incrementing is too heavyweight a response.
278 
279     if (onComplete) {
280         onComplete();
281     }
282     EmulatedEglFenceSync::incrementTimelineAndDeleteOldFences();
283 
284     DPRINT("done timeline increment");
285 
286     DPRINT("exit");
287 }
288 
289 #endif
290 
triggerWaitVk(VkFence vkFence,uint64_t timeline)291 void SyncThread::triggerWaitVk(VkFence vkFence, uint64_t timeline) {
292     std::stringstream ss;
293     ss << "triggerWaitVk vkFence=0x" << std::hex << reinterpret_cast<uintptr_t>(vkFence)
294        << " timeline=0x" << std::hex << timeline;
295     sendAsync(
296         [vkFence, timeline](WorkerId) {
297             doSyncWaitVk(vkFence, [timeline] {
298                 DPRINT("vk wait done, use goldfish sync timeline inc");
299                 emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
300             });
301         },
302         ss.str());
303 }
304 
triggerWaitVkWithCompletionCallback(VkFence vkFence,FenceCompletionCallback cb)305 void SyncThread::triggerWaitVkWithCompletionCallback(VkFence vkFence, FenceCompletionCallback cb) {
306     std::stringstream ss;
307     ss << "triggerWaitVkWithCompletionCallback vkFence=0x" << std::hex
308        << reinterpret_cast<uintptr_t>(vkFence);
309     sendAsync([vkFence, cb = std::move(cb)](WorkerId) { doSyncWaitVk(vkFence, std::move(cb)); },
310               ss.str());
311 }
312 
triggerWaitVkQsriWithCompletionCallback(VkImage vkImage,FenceCompletionCallback cb)313 void SyncThread::triggerWaitVkQsriWithCompletionCallback(VkImage vkImage, FenceCompletionCallback cb) {
314     std::stringstream ss;
315     ss << "triggerWaitVkQsriWithCompletionCallback vkImage=0x"
316        << reinterpret_cast<uintptr_t>(vkImage);
317     sendAsync(
318         [vkImage, cb = std::move(cb)](WorkerId) {
319             auto decoder = vk::VkDecoderGlobalState::get();
320             auto res = decoder->registerQsriCallback(vkImage, cb);
321             // If registerQsriCallback does not schedule the callback, we still need to complete
322             // the task, otherwise we may hit deadlocks on tasks on the same ring.
323             if (!res.CallbackScheduledOrFired()) {
324                 cb();
325             }
326         },
327         ss.str());
328 }
329 
triggerWaitVkQsri(VkImage vkImage,uint64_t timeline)330 void SyncThread::triggerWaitVkQsri(VkImage vkImage, uint64_t timeline) {
331      std::stringstream ss;
332     ss << "triggerWaitVkQsri vkImage=0x" << std::hex << vkImage
333        << " timeline=0x" << std::hex << timeline;
334     sendAsync(
335         [vkImage, timeline](WorkerId) {
336             auto decoder = vk::VkDecoderGlobalState::get();
337             auto res = decoder->registerQsriCallback(vkImage, [timeline](){
338                  emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
339             });
340             // If registerQsriCallback does not schedule the callback, we still need to complete
341             // the task, otherwise we may hit deadlocks on tasks on the same ring.
342             if (!res.CallbackScheduledOrFired()) {
343                 emugl::emugl_sync_timeline_inc(timeline, kTimelineInterval);
344             }
345         },
346         ss.str());
347 }
348 
triggerGeneral(FenceCompletionCallback cb,std::string description)349 void SyncThread::triggerGeneral(FenceCompletionCallback cb, std::string description) {
350     std::stringstream ss;
351     ss << "triggerGeneral: " << description;
352     sendAsync(std::bind(std::move(cb)), ss.str());
353 }
354 
cleanup()355 void SyncThread::cleanup() {
356     sendAndWaitForResult(
357         [this](WorkerId workerId) {
358 #if GFXSTREAM_ENABLE_HOST_GLES
359             if (mHasGl) {
360                 const EGLDispatch* egl = gl::LazyLoadedEGLDispatch::get();
361 
362                 egl->eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
363 
364                 egl->eglDestroyContext(mDisplay, mContext[workerId]);
365                 egl->eglDestroySurface(mDisplay, mSurface[workerId]);
366                 mContext[workerId] = EGL_NO_CONTEXT;
367                 mSurface[workerId] = EGL_NO_SURFACE;
368             }
369 #endif
370             return 0;
371         },
372         "cleanup");
373     DPRINT("signal");
374     mLock.lock();
375     mExiting = true;
376     mCv.signalAndUnlock(&mLock);
377     DPRINT("exit");
378     // Wait for the control thread to exit. We can't destroy the SyncThread
379     // before we wait the control thread.
380     if (!wait(nullptr)) {
381         ERR("Fail to wait the control thread of the SyncThread to exit.");
382     }
383 }
384 
385 // Private methods below////////////////////////////////////////////////////////
386 
main()387 intptr_t SyncThread::main() {
388     DPRINT("in sync thread");
389     mLock.lock();
390     mCv.wait(&mLock, [this] { return mExiting; });
391 
392     mWorkerThreadPool.done();
393     mWorkerThreadPool.join();
394     DPRINT("exited sync thread");
395     return 0;
396 }
397 
sendAndWaitForResult(std::function<int (WorkerId)> job,std::string description)398 int SyncThread::sendAndWaitForResult(std::function<int(WorkerId)> job, std::string description) {
399     DPRINT("sendAndWaitForResult task(%s)", description.c_str());
400     std::packaged_task<int(WorkerId)> task(std::move(job));
401     std::future<int> resFuture = task.get_future();
402     Command command = {
403         .mTask = std::move(task),
404         .mDescription = std::move(description),
405     };
406 
407     mWorkerThreadPool.enqueue(std::move(command));
408     auto res = resFuture.get();
409     DPRINT("exit");
410     return res;
411 }
412 
sendAsync(std::function<void (WorkerId)> job,std::string description)413 void SyncThread::sendAsync(std::function<void(WorkerId)> job, std::string description) {
414     DPRINT("send task(%s)", description.c_str());
415     mWorkerThreadPool.enqueue(Command{
416         .mTask =
417             std::packaged_task<int(WorkerId)>([job = std::move(job)](WorkerId workerId) mutable {
418                 job(workerId);
419                 return 0;
420             }),
421         .mDescription = std::move(description),
422     });
423     DPRINT("exit");
424 }
425 
doSyncThreadCmd(Command && command,WorkerId workerId)426 void SyncThread::doSyncThreadCmd(Command&& command, WorkerId workerId) {
427     std::unique_ptr<std::unordered_map<std::string, std::string>> syncThreadData =
428         std::make_unique<std::unordered_map<std::string, std::string>>();
429     syncThreadData->insert({{"syncthread_cmd_desc", command.mDescription}});
430     auto watchdog = WATCHDOG_BUILDER(mHealthMonitor, "SyncThread task execution")
431                         .setHangType(EventHangMetadata::HangType::kSyncThread)
432                         .setAnnotations(std::move(syncThreadData))
433                         .build();
434     command.mTask(workerId);
435 }
436 
doSyncWaitVk(VkFence vkFence,std::function<void ()> onComplete)437 int SyncThread::doSyncWaitVk(VkFence vkFence, std::function<void()> onComplete) {
438     DPRINT("enter");
439 
440     auto decoder = vk::VkDecoderGlobalState::get();
441     auto result = decoder->waitForFence(vkFence, kDefaultTimeoutNsecs);
442     if (result == VK_TIMEOUT) {
443         DPRINT("SYNC_WAIT_VK timeout: vkFence=%p", vkFence);
444     } else if (result != VK_SUCCESS) {
445         DPRINT("SYNC_WAIT_VK error: %d vkFence=%p", result, vkFence);
446     }
447 
448     DPRINT("issue timeline increment");
449 
450     // We always unconditionally increment timeline at this point, even
451     // if the call to vkWaitForFences returned abnormally.
452     // See comments in |doSyncWait| about the rationale.
453     if (onComplete) {
454         onComplete();
455     }
456 
457     DPRINT("done timeline increment");
458 
459     DPRINT("exit");
460     return result;
461 }
462 
463 /* static */
get()464 SyncThread* SyncThread::get() {
465     auto res = sGlobalSyncThread()->syncThreadPtr();
466     SYNC_THREAD_CHECK(res);
467     return res;
468 }
469 
initialize(bool hasGl,HealthMonitor<> * healthMonitor)470 void SyncThread::initialize(bool hasGl, HealthMonitor<>* healthMonitor) {
471     sGlobalSyncThread()->initialize(hasGl, healthMonitor);
472 }
473 
destroy()474 void SyncThread::destroy() { sGlobalSyncThread()->destroy(); }
475 
476 }  // namespace gfxstream
477