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