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