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