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