• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "FenceSync.h"
20 
21 #include <EGL/egl.h>
22 #include <GLES2/gl2.h>
23 #include <GLES2/gl2ext.h>
24 
25 #include "base/Optional.h"
26 #include "base/ConditionVariable.h"
27 #include "base/Lock.h"
28 #include "base/Thread.h"
29 #include "base/ThreadPool.h"
30 #include "base/MessageChannel.h"
31 #include "vulkan/VkDecoderGlobalState.h"
32 
33 // SyncThread///////////////////////////////////////////////////////////////////
34 // The purpose of SyncThread is to track sync device timelines and give out +
35 // signal FD's that correspond to the completion of host-side GL fence commands.
36 
37 // We communicate with the sync thread in 3 ways:
38 enum SyncThreadOpCode {
39     // Nonblocking command to initialize sync thread's contents,
40     // such as the EGL context for sync operations
41     SYNC_THREAD_INIT = 0,
42     // Nonblocking command to wait on a given FenceSync object
43     // and timeline handle.
44     // A fence FD object in the guest is signaled.
45     SYNC_THREAD_WAIT = 1,
46     // Blocking command to clean up and exit the sync thread.
47     SYNC_THREAD_EXIT = 2,
48     // Blocking command to wait on a given FenceSync object.
49     // No timeline handling is done.
50     SYNC_THREAD_BLOCKED_WAIT_NO_TIMELINE = 3,
51     // Nonblocking command to wait on a given VkFence
52     // and timeline handle.
53     // A fence FD object / Zircon eventpair in the guest is signaled.
54     SYNC_THREAD_WAIT_VK = 4,
55 };
56 
57 struct SyncThreadCmd {
58     SyncThreadOpCode opCode = SYNC_THREAD_INIT;
59     union {
60         FenceSync* fenceSync = nullptr;
61         VkFence vkFence;
62     };
63     uint64_t timeline = 0;
64 
65     android::base::Lock* lock = nullptr;
66     android::base::ConditionVariable* cond = nullptr;
67     android::base::Optional<int>* result = nullptr;
68 };
69 
70 struct RenderThreadInfo;
71 class SyncThread : public android::base::Thread {
72 public:
73     // - constructor: start up the sync worker threads for a given context.
74     // The initialization of the sync threads is nonblocking.
75     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_INIT|
76     SyncThread();
77     ~SyncThread();
78 
79     // |triggerWait|: async wait with a given FenceSync object.
80     // We use the wait() method to do a eglClientWaitSyncKHR.
81     // After wait is over, the timeline will be incremented,
82     // which should signal the guest-side fence FD.
83     // This method is how the goldfish sync virtual device
84     // knows when to increment timelines / signal native fence FD's.
85     void triggerWait(FenceSync* fenceSync,
86                      uint64_t timeline);
87 
88     // |triggerWaitVk|: async wait with a given VkFence object.
89     // The |vkFence| argument is a *boxed* host Vulkan handle of the fence.
90     //
91     // We call vkWaitForFences() on host Vulkan device to wait for the fence.
92     // After wait is over, the timeline will be incremented,
93     // which should signal the guest-side fence FD / Zircon eventpair.
94     // This method is how the goldfish sync virtual device
95     // knows when to increment timelines / signal native fence FD's.
96     void triggerWaitVk(VkFence vkFence, uint64_t timeline);
97 
98     // for use with the virtio-gpu path; is meant to have a current context
99     // while waiting.
100     void triggerBlockedWaitNoTimeline(FenceSync* fenceSync);
101 
102     // |cleanup|: for use with destructors and other cleanup functions.
103     // it destroys the sync context and exits the sync thread.
104     // This is blocking; after this function returns, we're sure
105     // the sync thread is gone.
106     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_EXIT|
107     void cleanup();
108 
109     // Obtains the global sync thread.
110     static SyncThread* get();
111 
112     // Destroys and recreates the sync thread, for use on snapshot load.
113     static void destroy();
114     static void recreate();
115 
116 private:
117     // |initSyncContext| creates an EGL context expressly for calling
118     // eglClientWaitSyncKHR in the processing caused by |triggerWait|.
119     // This is used by the constructor only. It is non-blocking.
120     // - Triggers a |SyncThreadCmd| with op code |SYNC_THREAD_INIT|
121     void initSyncContext();
122 
123     // Thread function.
124     // It keeps the workers runner until |mExiting| is set.
125     virtual intptr_t main() override final;
126 
127     // These two functions are used to communicate with the sync thread
128     // from another thread:
129     // - |sendAndWaitForResult| issues |cmd| to the sync thread,
130     //   and blocks until it receives the result of the command.
131     // - |sendAsync| issues |cmd| to the sync thread and does not
132     //   wait for the result, returning immediately after.
133     int sendAndWaitForResult(SyncThreadCmd& cmd);
134     void sendAsync(SyncThreadCmd& cmd);
135 
136     // |doSyncThreadCmd| and related functions below
137     // execute the actual commands. These run on the sync thread.
138     int doSyncThreadCmd(SyncThreadCmd* cmd);
139     void doSyncContextInit();
140     void doSyncWait(SyncThreadCmd* cmd);
141     int doSyncWaitVk(SyncThreadCmd* cmd);
142     void doSyncBlockedWaitNoTimeline(SyncThreadCmd* cmd);
143     void doExit();
144 
145     // EGL objects / object handles specific to
146     // a sync thread.
147     EGLDisplay mDisplay = EGL_NO_DISPLAY;
148     EGLContext mContext = EGL_NO_CONTEXT;
149     EGLSurface mSurface = EGL_NO_SURFACE;
150 
151     bool mExiting = false;
152     android::base::Lock mLock;
153     android::base::ConditionVariable mCv;
154     android::base::ThreadPool<SyncThreadCmd> mWorkerThreadPool;
155 };
156 
157