1 /* 2 * Copyright (C) 2018 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 #undef NDEBUG 20 21 #include <cassert> 22 #include <condition_variable> 23 #include <cstdint> 24 #include <map> 25 #include <mutex> 26 #include <string> 27 #include <thread> 28 29 #include "GLESv1.h" 30 #include "GLESv3.h" 31 #include "RenderControl.h" 32 #include "Resource.h" 33 34 struct EglContext; 35 struct Context; 36 37 typedef void (*PFNSUBMITCMD)(Context*, char*, size_t, int); 38 39 struct Context { 40 static std::map<uint32_t, Context*> map; 41 ContextContext42 Context(uint32_t handle_, const char* name_, uint32_t nlen_, PFNSUBMITCMD pfnProcessCmd_, 43 EGLDisplay dpy_) 44 : render_control(this, dpy_), worker(), name(std::string(name_, nlen_)), handle(handle_), 45 pfnProcessCmd(pfnProcessCmd_) { 46 map.emplace(handle, this); 47 reset(); 48 } 49 ~ContextContext50 ~Context() { 51 { 52 std::lock_guard<std::mutex> lk(m); 53 killWorker = true; 54 } 55 cv.notify_one(); 56 if (worker.joinable()) 57 worker.join(); 58 map.erase(handle); 59 } 60 bindContext61 Context* bind(EglContext* ctx_) { 62 for (auto const& it : Context::map) { 63 Context* ctx = it.second; 64 if (ctx == this) 65 continue; 66 if (ctx->ctx == ctx_) 67 return ctx; 68 } 69 ctx = ctx_; 70 return nullptr; 71 } 72 unbindContext73 void unbind() { 74 ctx = nullptr; 75 } 76 setPidTidContext77 void setPidTid(int pid_, int tid_) { 78 if (pid != pid_ && tid != tid_) { 79 assert(!worker.joinable() && "Changing pid/tid is not allowed"); 80 worker = std::thread(&Context::worker_func, this); 81 } 82 pid = pid_; 83 tid = tid_; 84 } 85 submitCommandContext86 void submitCommand(void* buf, size_t bufSize) { 87 char* cmdBufCopy = new char[bufSize]; 88 memcpy(cmdBufCopy, buf, bufSize); 89 { 90 std::lock_guard<std::mutex> lk(m); 91 cmdBufSize = bufSize; 92 cmdBuf = cmdBufCopy; 93 } 94 cv.notify_one(); 95 } 96 setFenceContext97 void setFence(int fence_) { 98 { 99 std::lock_guard<std::mutex> lk(m); 100 fence = fence_; 101 if (!worker.joinable()) 102 processCmd(); 103 } 104 cv.notify_one(); 105 } 106 107 std::map<uint32_t, Resource*> resource_map; 108 ChecksumCalculator checksum_calc; 109 RenderControl render_control; 110 Resource* cmd_resp = nullptr; 111 EglContext* ctx = nullptr; 112 std::thread worker; 113 std::string name; 114 uint32_t handle; 115 GLESv1 gles1; 116 GLESv3 gles3; 117 int pid = 0; 118 int tid = 0; 119 120 private: 121 std::condition_variable cv; 122 PFNSUBMITCMD pfnProcessCmd; 123 bool killWorker = false; 124 size_t cmdBufSize; 125 char* cmdBuf; 126 std::mutex m; 127 int fence; 128 resetContext129 void reset() { 130 cmdBuf = nullptr; 131 cmdBufSize = 0U; 132 fence = 0; 133 } 134 worker_funcContext135 void worker_func() { 136 while (!killWorker) { 137 std::unique_lock<std::mutex> lk(m); 138 cv.wait(lk, [this] { return killWorker || (cmdBuf && fence); }); 139 if (!killWorker) 140 processCmd(); 141 lk.unlock(); 142 } 143 } 144 processCmdContext145 void processCmd() { 146 pfnProcessCmd(this, cmdBuf, cmdBufSize, fence); 147 delete cmdBuf; 148 reset(); 149 } 150 }; 151