1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pixel_map_program_manager.h"
17 #include <memory>
18
19 #undef LOG_TAG
20 #define LOG_TAG "PixelMapProgramManager"
21
22 namespace OHOS {
23 namespace Media {
24 static const int MAX_GL_INSTANCE_NUM = 8;
25 constexpr int32_t MAX_CONTEXT_EXPIRED_TIME_SEC = 120;
26 constexpr int32_t MIN_CONTEXT_EXPIRED_TIME_SEC = 10;
27 static vector<PixelMapGLPostProcProgram *> g_availInstances;
28 static std::mutex g_contextMutex;
29 static std::mutex g_shaderBuildMutex;
30 static std::atomic<int> g_nowInstanceNum = 0;
31 static std::atomic<bool> g_destroyThreadIsRunning = false;
32 static std::atomic<long> g_lastTouchInstanceTime = 0;
33 static std::condition_variable g_dataCond;
34
PixelMapProgramManager()35 PixelMapProgramManager::PixelMapProgramManager() noexcept
36 {
37 }
38
~PixelMapProgramManager()39 PixelMapProgramManager::~PixelMapProgramManager() noexcept
40 {
41 }
42
GetInstance()43 PixelMapProgramManager &PixelMapProgramManager::GetInstance() noexcept
44 {
45 static PixelMapProgramManager instance;
46 return instance;
47 }
48
GetProgram()49 PixelMapGLPostProcProgram* PixelMapProgramManager::GetProgram()
50 {
51 ImageTrace imageTrace("PixelMapProgramManager::GetProgram");
52 PixelMapGLPostProcProgram *program = nullptr;
53 std::unique_lock<std::mutex> locker(g_contextMutex);
54 struct timespec tv;
55 clock_gettime(CLOCK_MONOTONIC, &tv);
56 g_lastTouchInstanceTime = tv.tv_sec;
57 if (g_availInstances.size() > 0) {
58 program = g_availInstances.back();
59 g_availInstances.pop_back();
60 }
61 if (program != nullptr) {
62 return program;
63 }
64 if (g_nowInstanceNum >= MAX_GL_INSTANCE_NUM) {
65 int num = g_nowInstanceNum;
66 while (program == nullptr) {
67 if (g_dataCond.wait_for(locker, std::chrono::seconds(1)) == std::cv_status::timeout) {
68 IMAGE_LOGE("slr_gpu %{public}s GetInstance failed for wait timeout(%{public}d)", __func__, num);
69 return nullptr;
70 }
71 if (g_availInstances.size() > 0) {
72 program = g_availInstances.back();
73 g_availInstances.pop_back();
74 }
75 }
76 } else {
77 g_nowInstanceNum++;
78 locker.unlock();
79 program = new PixelMapGLPostProcProgram();
80 if (!program->Init()) {
81 std::unique_lock<std::mutex> locker(g_contextMutex);
82 g_nowInstanceNum--;
83 delete program;
84 program = nullptr;
85 } else {
86 int num = g_nowInstanceNum;
87 IMAGE_LOGI("slr_gpu %{public}s new instance(%{public}d)", __func__, num);
88 }
89 }
90 return program;
91 }
92
ReleaseInstance(PixelMapGLPostProcProgram * program)93 void PixelMapProgramManager::ReleaseInstance(PixelMapGLPostProcProgram *program)
94 {
95 {
96 std::unique_lock<std::mutex> locker(g_contextMutex);
97 g_availInstances.push_back(program);
98 }
99 g_dataCond.notify_one();
100 bool oldValue = false;
101 if (g_destroyThreadIsRunning.compare_exchange_weak(oldValue, true, std::memory_order_relaxed)) {
102 std::thread destroyInstanceThread(PixelMapProgramManager::DestoryInstanceThreadFunc);
103 destroyInstanceThread.detach();
104 }
105 }
106
DestoryInstanceThreadFunc()107 void PixelMapProgramManager::DestoryInstanceThreadFunc()
108 {
109 while (g_nowInstanceNum != 0) {
110 struct timespec tv;
111 clock_gettime(CLOCK_MONOTONIC, &tv);
112 long expiredTime = tv.tv_sec - g_lastTouchInstanceTime;
113 if (expiredTime < 0) {
114 expiredTime = 0;
115 }
116
117 if (g_nowInstanceNum > 1) {
118 if (expiredTime < MIN_CONTEXT_EXPIRED_TIME_SEC * (MAX_GL_INSTANCE_NUM + 1 - g_nowInstanceNum)) {
119 sleep(MIN_CONTEXT_EXPIRED_TIME_SEC);
120 continue;
121 }
122 } else {
123 if (expiredTime < MAX_CONTEXT_EXPIRED_TIME_SEC) {
124 sleep(MAX_CONTEXT_EXPIRED_TIME_SEC);
125 continue;
126 }
127 }
128 DestroyOneInstance();
129 }
130 g_destroyThreadIsRunning = false;
131 }
132
DestroyOneInstance()133 void PixelMapProgramManager::DestroyOneInstance()
134 {
135 std::unique_lock<std::mutex> locker(g_contextMutex);
136 PixelMapGLPostProcProgram *instance = nullptr;
137 if (g_availInstances.size() > 0) {
138 instance = g_availInstances.back();
139 g_availInstances.pop_back();
140 g_nowInstanceNum--;
141 if (instance != nullptr) delete instance;
142 }
143 int num = g_nowInstanceNum;
144 IMAGE_LOGE("slr_gpu %{public}s destroy opengl context(%{public}d)", __func__, num);
145 }
146
BuildShader()147 bool PixelMapProgramManager::BuildShader()
148 {
149 return PixelMapGLPostProcProgram::BuildShader();
150 }
151
ExecutProgram(PixelMapGLPostProcProgram * program)152 bool PixelMapProgramManager::ExecutProgram(PixelMapGLPostProcProgram *program)
153 {
154 if (program == nullptr) {
155 IMAGE_LOGE("slr_gpu ExecutProgram program is nullptr");
156 return false;
157 }
158 bool ret = program->Execute();
159 if (!ret) {
160 IMAGE_LOGE("slr_gpu ExecutProgram failed");
161 {
162 std::unique_lock<std::mutex> locker(g_contextMutex);
163 g_nowInstanceNum--;
164 }
165 delete program;
166 program = nullptr;
167 return false;
168 }
169 ReleaseInstance(program);
170 return ret;
171 }
172 } // namespace Media
173 } // namespace OHOS