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