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