| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #undef NDEBUG |
| |
| #include <cassert> |
| #include <condition_variable> |
| #include <cstdint> |
| #include <map> |
| #include <mutex> |
| #include <string> |
| #include <thread> |
| |
| #include "GLESv1.h" |
| #include "GLESv3.h" |
| #include "RenderControl.h" |
| #include "Resource.h" |
| |
| struct EglContext; |
| struct Context; |
| |
| typedef void (*PFNSUBMITCMD)(Context*, char*, size_t, int); |
| |
| struct Context { |
| static std::map<uint32_t, Context*> map; |
| |
| Context(uint32_t handle_, const char* name_, uint32_t nlen_, PFNSUBMITCMD pfnProcessCmd_, |
| EGLDisplay dpy_) |
| : render_control(this, dpy_), worker(), name(std::string(name_, nlen_)), handle(handle_), |
| pfnProcessCmd(pfnProcessCmd_) { |
| map.emplace(handle, this); |
| reset(); |
| } |
| |
| ~Context() { |
| { |
| std::lock_guard<std::mutex> lk(m); |
| killWorker = true; |
| } |
| cv.notify_one(); |
| if (worker.joinable()) |
| worker.join(); |
| map.erase(handle); |
| } |
| |
| Context* bind(EglContext* ctx_) { |
| for (auto const& it : Context::map) { |
| Context* ctx = it.second; |
| if (ctx == this) |
| continue; |
| if (ctx->ctx == ctx_) |
| return ctx; |
| } |
| ctx = ctx_; |
| return nullptr; |
| } |
| |
| void unbind() { |
| ctx = nullptr; |
| } |
| |
| void setPidTid(int pid_, int tid_) { |
| if (pid != pid_ && tid != tid_) { |
| assert(!worker.joinable() && "Changing pid/tid is not allowed"); |
| worker = std::thread(&Context::worker_func, this); |
| } |
| pid = pid_; |
| tid = tid_; |
| } |
| |
| void submitCommand(void* buf, size_t bufSize) { |
| char* cmdBufCopy = new char[bufSize]; |
| memcpy(cmdBufCopy, buf, bufSize); |
| { |
| std::lock_guard<std::mutex> lk(m); |
| cmdBufSize = bufSize; |
| cmdBuf = cmdBufCopy; |
| } |
| cv.notify_one(); |
| } |
| |
| void setFence(int fence_) { |
| { |
| std::lock_guard<std::mutex> lk(m); |
| fence = fence_; |
| if (!worker.joinable()) |
| processCmd(); |
| } |
| cv.notify_one(); |
| } |
| |
| std::map<uint32_t, Resource*> resource_map; |
| ChecksumCalculator checksum_calc; |
| RenderControl render_control; |
| Resource* cmd_resp = nullptr; |
| EglContext* ctx = nullptr; |
| std::thread worker; |
| std::string name; |
| uint32_t handle; |
| GLESv1 gles1; |
| GLESv3 gles3; |
| int pid = 0; |
| int tid = 0; |
| |
| private: |
| std::condition_variable cv; |
| PFNSUBMITCMD pfnProcessCmd; |
| bool killWorker = false; |
| size_t cmdBufSize; |
| char* cmdBuf; |
| std::mutex m; |
| int fence; |
| |
| void reset() { |
| cmdBuf = nullptr; |
| cmdBufSize = 0U; |
| fence = 0; |
| } |
| |
| void worker_func() { |
| while (!killWorker) { |
| std::unique_lock<std::mutex> lk(m); |
| cv.wait(lk, [this] { return killWorker || (cmdBuf && fence); }); |
| if (!killWorker) |
| processCmd(); |
| lk.unlock(); |
| } |
| } |
| |
| void processCmd() { |
| pfnProcessCmd(this, cmdBuf, cmdBufSize, fence); |
| delete cmdBuf; |
| reset(); |
| } |
| }; |