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