1 /*
2 * Copyright (c) 2022 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 "rs_egl_image_manager.h"
17
18 #include <native_window.h>
19 #include <platform/common/rs_log.h>
20 #include "sync_fence.h"
21 #include "pipeline/rs_main_thread.h"
22 #include "pipeline/rs_hardware_thread.h"
23 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
24 #include "rs_trace.h"
25 #include "common/rs_optional_trace.h"
26 #include "pipeline/rs_task_dispatcher.h"
27
28 #ifndef NDEBUG
29 #include <cassert>
30 #endif
31
32 namespace OHOS {
33 namespace Rosen {
34 namespace Detail {
35 #ifdef NDEBUG
36 #define RS_ASSERT(exp) (void)((exp))
37 #else
38 #define RS_ASSERT(exp) assert((exp))
39 #endif
40
41 #define RS_EGL_ERR_CASE_STR(value) case value: return #value
EGLErrorString(GLint error)42 const char *EGLErrorString(GLint error)
43 {
44 switch (error) {
45 RS_EGL_ERR_CASE_STR(EGL_SUCCESS);
46 RS_EGL_ERR_CASE_STR(EGL_NOT_INITIALIZED);
47 RS_EGL_ERR_CASE_STR(EGL_BAD_ACCESS);
48 RS_EGL_ERR_CASE_STR(EGL_BAD_ALLOC);
49 RS_EGL_ERR_CASE_STR(EGL_BAD_ATTRIBUTE);
50 RS_EGL_ERR_CASE_STR(EGL_BAD_CONFIG);
51 RS_EGL_ERR_CASE_STR(EGL_BAD_CONTEXT);
52 RS_EGL_ERR_CASE_STR(EGL_BAD_CURRENT_SURFACE);
53 RS_EGL_ERR_CASE_STR(EGL_BAD_DISPLAY);
54 RS_EGL_ERR_CASE_STR(EGL_BAD_MATCH);
55 RS_EGL_ERR_CASE_STR(EGL_BAD_NATIVE_PIXMAP);
56 RS_EGL_ERR_CASE_STR(EGL_BAD_NATIVE_WINDOW);
57 RS_EGL_ERR_CASE_STR(EGL_BAD_PARAMETER);
58 RS_EGL_ERR_CASE_STR(EGL_BAD_SURFACE);
59 RS_EGL_ERR_CASE_STR(EGL_CONTEXT_LOST);
60 default: return "Unknown";
61 }
62 }
63
GetEGLCreateImageKHRFunc()64 static PFNEGLCREATEIMAGEKHRPROC GetEGLCreateImageKHRFunc()
65 {
66 static auto func = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
67 return func;
68 }
69
GetEGLDestroyImageKHRFunc()70 static PFNEGLDESTROYIMAGEKHRPROC GetEGLDestroyImageKHRFunc()
71 {
72 static auto func = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
73 return func;
74 }
75
GetGLEGLImageTargetTexture2DOESFunc()76 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC GetGLEGLImageTargetTexture2DOESFunc()
77 {
78 static auto func = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
79 eglGetProcAddress("glEGLImageTargetTexture2DOES"));
80 return func;
81 }
82
83 // RAII object for NativeWindowBuffer
84 class NativeWindowBufferObject {
85 public:
NativeWindowBufferObject(sptr<OHOS::SurfaceBuffer> buffer)86 explicit NativeWindowBufferObject(sptr<OHOS::SurfaceBuffer> buffer)
87 : handle_(CreateNativeWindowBufferFromSurfaceBuffer(&buffer))
88 {
89 }
NativeWindowBufferObject(NativeWindowBuffer * nativeBuffer)90 explicit NativeWindowBufferObject(NativeWindowBuffer* nativeBuffer)
91 : handle_(nativeBuffer)
92 {
93 }
94
~NativeWindowBufferObject()95 ~NativeWindowBufferObject() noexcept
96 {
97 if (handle_ != nullptr) {
98 DestroyNativeWindowBuffer(handle_);
99 }
100 }
101
102 NativeWindowBufferObject(const NativeWindowBufferObject&) = delete;
103 void operator=(const NativeWindowBufferObject&) = delete;
104
operator ==(std::nullptr_t) const105 bool operator==(std::nullptr_t) const
106 {
107 return handle_ == nullptr;
108 }
operator !=(std::nullptr_t) const109 bool operator!=(std::nullptr_t) const
110 {
111 return handle_ != nullptr;
112 }
113
114 // not explicit so you can use it to do the implicit-cast.
115 // you should not delete or call DestroyNativeWindowBuffer for this pointer.
116 operator NativeWindowBuffer* () const
117 {
118 return Get();
119 }
120 // you should not delete or call DestroyNativeWindowBuffer for this pointer.
Get() const121 NativeWindowBuffer* Get() const
122 {
123 return handle_;
124 }
125
Release()126 NativeWindowBuffer* Release()
127 {
128 NativeWindowBuffer* out = handle_;
129 handle_ = nullptr;
130 return out;
131 }
132
133 private:
134 NativeWindowBuffer* handle_ = nullptr;
135 };
136
CreateNativeWindowBuffer(const sptr<OHOS::SurfaceBuffer> & buffer)137 NativeWindowBufferObject CreateNativeWindowBuffer(const sptr<OHOS::SurfaceBuffer>& buffer)
138 {
139 return NativeWindowBufferObject(buffer);
140 }
141
CastToEGLClientBuffer(NativeWindowBuffer * nativeBuffer)142 EGLClientBuffer CastToEGLClientBuffer(NativeWindowBuffer* nativeBuffer)
143 {
144 return static_cast<EGLClientBuffer>(nativeBuffer);
145 }
146
CastFromEGLClientBuffer(EGLClientBuffer eglClientBuffer)147 NativeWindowBuffer* CastFromEGLClientBuffer(EGLClientBuffer eglClientBuffer)
148 {
149 return static_cast<NativeWindowBuffer*>(eglClientBuffer);
150 }
151
CreateEGLImage(EGLDisplay eglDisplay,EGLContext eglContext,const NativeWindowBufferObject & nativeBuffer)152 EGLImageKHR CreateEGLImage(
153 EGLDisplay eglDisplay,
154 EGLContext eglContext,
155 const NativeWindowBufferObject& nativeBuffer)
156 {
157 EGLint attrs[] = {
158 EGL_IMAGE_PRESERVED_KHR,
159 EGL_TRUE,
160 EGL_NONE,
161 };
162
163 return GetEGLCreateImageKHRFunc()(
164 eglDisplay, eglContext, EGL_NATIVE_BUFFER_OHOS, CastToEGLClientBuffer(nativeBuffer), attrs);
165 }
166 } // namespace Detail
167
ImageCacheSeq(EGLDisplay eglDisplay,EGLImageKHR eglImage,EGLClientBuffer eglClientBuffer)168 ImageCacheSeq::ImageCacheSeq(
169 EGLDisplay eglDisplay, EGLImageKHR eglImage, EGLClientBuffer eglClientBuffer)
170 : eglDisplay_(eglDisplay),
171 eglImage_(eglImage),
172 eglClientBuffer_(eglClientBuffer)
173 {
174 }
175
~ImageCacheSeq()176 ImageCacheSeq::~ImageCacheSeq() noexcept
177 {
178 if (eglImage_ != EGL_NO_IMAGE_KHR) {
179 Detail::GetEGLDestroyImageKHRFunc()(eglDisplay_, eglImage_);
180 eglImage_ = EGL_NO_IMAGE_KHR;
181 }
182
183 if (textureId_ != 0) {
184 glDeleteTextures(1, &textureId_);
185 textureId_ = 0;
186 }
187
188 // auto dec ref.
189 Detail::NativeWindowBufferObject nBufferDecRef(
190 Detail::CastFromEGLClientBuffer(eglClientBuffer_));
191 }
192
BindToTexture()193 bool ImageCacheSeq::BindToTexture()
194 {
195 // no image check.
196 if (eglImage_ == EGL_NO_IMAGE_KHR) {
197 RS_LOGE("ImageCacheSeq::BindToTexture: eglImage_ is null.");
198 return false;
199 }
200
201 glGenTextures(1, &textureId_);
202 if (textureId_ == 0) {
203 RS_LOGE("ImageCacheSeq::BindToTexture: glGenTextures error.");
204 return false;
205 }
206
207 // bind this eglImage_ to textureId_.
208 glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId_);
209 Detail::GetGLEGLImageTargetTexture2DOESFunc()(GL_TEXTURE_EXTERNAL_OES, eglImage_);
210 return true;
211 }
212
Create(EGLDisplay eglDisplay,EGLContext eglContext,const sptr<OHOS::SurfaceBuffer> & buffer)213 std::unique_ptr<ImageCacheSeq> ImageCacheSeq::Create(
214 EGLDisplay eglDisplay,
215 EGLContext eglContext,
216 const sptr<OHOS::SurfaceBuffer>& buffer)
217 {
218 auto nativeBuffer = Detail::CreateNativeWindowBuffer(buffer);
219 if (nativeBuffer == nullptr) {
220 return nullptr;
221 }
222
223 EGLImageKHR img = Detail::CreateEGLImage(eglDisplay, eglContext, nativeBuffer);
224 if (img == EGL_NO_IMAGE_KHR) {
225 RS_LOGE("ImageCacheSeq::Create: eglCreateImageKHR failed, error %{public}s.",
226 Detail::EGLErrorString(eglGetError()));
227 return nullptr;
228 }
229
230 auto imageCache = std::make_unique<ImageCacheSeq>(
231 eglDisplay, img, Detail::CastToEGLClientBuffer(nativeBuffer.Release()));
232 if (!imageCache->BindToTexture()) {
233 return nullptr;
234 }
235 return imageCache;
236 }
237
RSEglImageManager(EGLDisplay display)238 RSEglImageManager::RSEglImageManager(EGLDisplay display) : eglDisplay_(display)
239 {
240 }
241
WaitAcquireFence(const sptr<SyncFence> & acquireFence)242 void RSEglImageManager::WaitAcquireFence(const sptr<SyncFence>& acquireFence)
243 {
244 if (acquireFence == nullptr) {
245 return;
246 }
247 acquireFence->Wait(3000); // 3000ms
248 }
249
CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const pid_t threadIndex)250 GLuint RSEglImageManager::CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer>& buffer,
251 const pid_t threadIndex)
252 {
253 auto bufferId = buffer->GetSeqNum();
254 auto imageCache = ImageCacheSeq::Create(eglDisplay_, EGL_NO_CONTEXT, buffer);
255 if (imageCache == nullptr) {
256 RS_LOGE("RSEglImageManager::CreateImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
257 bufferId);
258 return 0; // return texture id 0.
259 }
260 imageCache->SetThreadIndex(threadIndex);
261 auto textureId = imageCache->TextureId();
262 {
263 std::lock_guard<std::mutex> lock(opMutex_);
264 imageCacheSeqs_[bufferId] = std::move(imageCache);
265 }
266 cacheQueue_.push(bufferId);
267 return textureId;
268 }
269
CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence)270 std::unique_ptr<ImageCacheSeq> RSEglImageManager::CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer>& buffer,
271 const sptr<SyncFence>& acquireFence)
272 {
273 WaitAcquireFence(acquireFence);
274 auto bufferId = buffer->GetSeqNum();
275 auto imageCache = ImageCacheSeq::Create(eglDisplay_, EGL_NO_CONTEXT, buffer);
276 if (imageCache == nullptr) {
277 RS_LOGE("RSEglImageManager::CreateImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
278 bufferId);
279 return nullptr;
280 }
281 return imageCache;
282 }
283
MapEglImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex)284 GLuint RSEglImageManager::MapEglImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer>& buffer,
285 const sptr<SyncFence>& acquireFence, pid_t threadIndex)
286 {
287 WaitAcquireFence(acquireFence);
288 auto bufferId = buffer->GetSeqNum();
289 RS_OPTIONAL_TRACE_NAME_FMT("MapEglImage seqNum: %d", bufferId);
290 RS_LOGD("RSEglImageManager::MapEglImageFromSurfaceBuffer: %{public}d", bufferId);
291 {
292 bool isImageCacheNotFound = false;
293 std::lock_guard<std::mutex> lock(opMutex_);
294 isImageCacheNotFound = imageCacheSeqs_.count(bufferId) == 0 || imageCacheSeqs_[bufferId] == nullptr;
295 if (!isImageCacheNotFound) {
296 const auto& imageCache = imageCacheSeqs_[bufferId];
297 return imageCache->TextureId();
298 }
299 }
300 // cache not found, create it.
301 return CreateImageCacheFromBuffer(buffer, threadIndex);
302 }
303
ShrinkCachesIfNeeded(bool isForUniRedraw)304 void RSEglImageManager::ShrinkCachesIfNeeded(bool isForUniRedraw)
305 {
306 while (cacheQueue_.size() > MAX_CACHE_SIZE) {
307 const int32_t id = cacheQueue_.front();
308 if (isForUniRedraw) {
309 UnMapEglImageFromSurfaceBufferForUniRedraw(id);
310 } else {
311 UnMapEglImageFromSurfaceBuffer(id);
312 }
313 cacheQueue_.pop();
314 }
315 }
316
UnMapEglImageFromSurfaceBuffer(int32_t seqNum)317 void RSEglImageManager::UnMapEglImageFromSurfaceBuffer(int32_t seqNum)
318 {
319 pid_t threadIndex = 0;
320 {
321 std::lock_guard<std::mutex> lock(opMutex_);
322 if (imageCacheSeqs_.count(seqNum) == 0) {
323 return;
324 }
325 if (imageCacheSeqs_[seqNum]) {
326 threadIndex = imageCacheSeqs_[seqNum]->GetThreadIndex();
327 }
328 }
329 auto func = [this, seqNum]() {
330 std::unique_ptr<ImageCacheSeq> imageCacheSeq;
331 {
332 std::lock_guard<std::mutex> lock(opMutex_);
333 if (imageCacheSeqs_.count(seqNum) == 0) {
334 return;
335 }
336 imageCacheSeq = std::move(imageCacheSeqs_[seqNum]);
337 }
338 imageCacheSeq.reset();
339 RS_OPTIONAL_TRACE_NAME_FMT("UnmapEglImage seqNum: %d", seqNum);
340 RS_LOGD("RSEglImageManager::UnMapEglImageFromSurfaceBuffer: %{public}d", seqNum);
341 };
342 RSTaskDispatcher::GetInstance().PostTask(threadIndex, func);
343 }
344
UnMapEglImageFromSurfaceBufferForUniRedraw(int32_t seqNum)345 void RSEglImageManager::UnMapEglImageFromSurfaceBufferForUniRedraw(int32_t seqNum)
346 {
347 RSHardwareThread::Instance().PostTask([this, seqNum]() {
348 std::lock_guard<std::mutex> lock(opMutex_);
349 if (imageCacheSeqs_.count(seqNum) == 0) {
350 return;
351 }
352 (void)imageCacheSeqs_.erase(seqNum);
353 RS_LOGD("RSEglImageManager::UnMapEglImageFromSurfaceBufferForRedraw");
354 });
355 }
356 } // namespace Rosen
357 } // namespace OHOS
358