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 #pragma once
18 
19 #if GFXSTREAM_ENABLE_HOST_GLES
20 #include <EGL/egl.h>
21 #include <GLES2/gl2.h>
22 #include <GLES2/gl2ext.h>
23 
24 #include "gl/EmulatedEglFenceSync.h"
25 #endif
26 
27 #include <functional>
28 #include <future>
29 #include <string>
30 #include <type_traits>
31 
32 #include "aemu/base/HealthMonitor.h"
33 #include "aemu/base/Optional.h"
34 #include "aemu/base/synchronization/ConditionVariable.h"
35 #include "aemu/base/synchronization/Lock.h"
36 #include "aemu/base/synchronization/MessageChannel.h"
37 #include "aemu/base/threads/Thread.h"
38 #include "aemu/base/threads/ThreadPool.h"
39 #include "render-utils/virtio_gpu_ops.h"
40 #include "vulkan/VkDecoderGlobalState.h"
41 
42 namespace gfxstream {
43 
44 using emugl::HealthMonitor;
45 using emugl::HealthWatchdog;
46 
47 // SyncThread///////////////////////////////////////////////////////////////////
48 // The purpose of SyncThread is to track sync device timelines and give out +
49 // signal FD's that correspond to the completion of host-side GL fence commands.
50 
51 struct RenderThreadInfo;
52 class SyncThread : public android::base::Thread {
53    public:
54     // - constructor: start up the sync worker threads for a given context.
55     // The initialization of the sync threads is nonblocking.
56     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EGL_INIT|
57     SyncThread(bool hasGl, HealthMonitor<>* healthMonitor);
58     ~SyncThread();
59 
60     // |triggerWaitVk|: async wait with a given VkFence object.
61     // The |vkFence| argument is a *boxed* host Vulkan handle of the fence.
62     //
63     // We call vkWaitForFences() on host Vulkan device to wait for the fence.
64     // After wait is over, the timeline will be incremented,
65     // which should signal the guest-side fence FD / Zircon eventpair.
66     // This method is how the goldfish sync virtual device
67     // knows when to increment timelines / signal native fence FD's.
68     void triggerWaitVk(VkFence vkFence, uint64_t timeline);
69 
70 #if GFXSTREAM_ENABLE_HOST_GLES
71     // |triggerWait|: async wait with a given EmulatedEglFenceSync object.
72     // We use the wait() method to do a eglClientWaitSyncKHR.
73     // After wait is over, the timeline will be incremented,
74     // which should signal the guest-side fence FD.
75     // This method is how the goldfish sync virtual device
76     // knows when to increment timelines / signal native fence FD's.
77     void triggerWait(gl::EmulatedEglFenceSync* fenceSync, uint64_t timeline);
78 
79     // for use with the virtio-gpu path; is meant to have a current context
80     // while waiting.
81     void triggerBlockedWaitNoTimeline(gl::EmulatedEglFenceSync* fenceSync);
82 
83     // For use with virtio-gpu and async fence completion callback. This is async like triggerWait,
84     // but takes a fence completion callback instead of incrementing some timeline directly.
85     void triggerWaitWithCompletionCallback(gl::EmulatedEglFenceSync* fenceSync,
86                                            FenceCompletionCallback);
87 
88     // |initSyncContext| creates an EGL context expressly for calling
89     // eglClientWaitSyncKHR in the processing caused by |triggerWait|.
90     // This is used by the constructor only. It is non-blocking.
91     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EGL_INIT|
92     void initSyncEGLContext();
93 
94     void doSyncWait(gl::EmulatedEglFenceSync* fenceSync, std::function<void()> onComplete);
95 #endif
96 
97     // This increments the timeline after the QSRI completes.
98     void triggerWaitVkQsri(VkImage vkImage, uint64_t timeline);
99 
100     void triggerWaitVkWithCompletionCallback(VkFence fenceHandle, FenceCompletionCallback);
101     void triggerWaitVkQsriWithCompletionCallback(VkImage image, FenceCompletionCallback);
102     void triggerGeneral(FenceCompletionCallback, std::string description);
103 
104     // |cleanup|: for use with destructors and other cleanup functions.
105     // it destroys the sync context and exits the sync thread.
106     // This is blocking; after this function returns, we're sure
107     // the sync thread is gone.
108     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EXIT|
109     void cleanup();
110 
111     // Initialize the global sync thread.
112     static void initialize(bool hasGl, HealthMonitor<>* healthMonitor);
113 
114     // Obtains the global sync thread.
115     static SyncThread* get();
116 
117     // Destroys and cleanup the global sync thread.
118     static void destroy();
119 
120    private:
121     using WorkerId = android::base::ThreadPoolWorkerId;
122     struct Command {
123         std::packaged_task<int(WorkerId)> mTask;
124         std::string mDescription;
125     };
126     using ThreadPool = android::base::ThreadPool<Command>;
127 
128     // Thread function.
129     // It keeps the workers runner until |mExiting| is set.
130     virtual intptr_t main() override final;
131 
132     // These two functions are used to communicate with the sync thread from another thread:
133     // - |sendAndWaitForResult| issues |job| to the sync thread, and blocks until it receives the
134     // result of the job.
135     // - |sendAsync| issues |job| to the sync thread and does not wait for the result, returning
136     // immediately after.
137     int sendAndWaitForResult(std::function<int(WorkerId)> job, std::string description);
138     void sendAsync(std::function<void(WorkerId)> job, std::string description);
139 
140     // |doSyncThreadCmd| execute the actual task. These run on the sync thread.
141     void doSyncThreadCmd(Command&& command, ThreadPool::WorkerId);
142 
143     static int doSyncWaitVk(VkFence, std::function<void()> onComplete);
144 
145     // EGL objects / object handles specific to
146     // a sync thread.
147     static const uint32_t kNumWorkerThreads = 4u;
148 
149 #if GFXSTREAM_ENABLE_HOST_GLES
150     EGLDisplay mDisplay = EGL_NO_DISPLAY;
151     EGLSurface mSurface[kNumWorkerThreads];
152     EGLContext mContext[kNumWorkerThreads];
153 #endif
154 
155     bool mExiting = false;
156     android::base::Lock mLock;
157     android::base::ConditionVariable mCv;
158     ThreadPool mWorkerThreadPool;
159     bool mHasGl;
160 
161     HealthMonitor<>* mHealthMonitor;
162 };
163 
164 }  // namespace gfxstream
165