• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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 "feature/uifirst/rs_sub_thread_manager.h"
19 #include <native_window.h>
20 #include <platform/common/rs_log.h>
21 #include "sync_fence.h"
22 #include "pipeline/main_thread/rs_main_thread.h"
23 #include "pipeline/hardware_thread/rs_hardware_thread.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 #ifdef USE_M133_SKIA
33 #include "src/gpu/ganesh/gl/GrGLDefines.h"
34 #else
35 #include "src/gpu/gl/GrGLDefines.h"
36 #endif
37 
38 namespace OHOS {
39 namespace Rosen {
40 namespace Detail {
41 #ifdef NDEBUG
42 #define RS_ASSERT(exp) (void)((exp))
43 #else
44 #define RS_ASSERT(exp) assert((exp))
45 #endif
46 
47 #define RS_EGL_ERR_CASE_STR(value) case value: return #value
EGLErrorString(GLint error)48 const char *EGLErrorString(GLint error)
49 {
50     switch (error) {
51         RS_EGL_ERR_CASE_STR(EGL_SUCCESS);
52         RS_EGL_ERR_CASE_STR(EGL_NOT_INITIALIZED);
53         RS_EGL_ERR_CASE_STR(EGL_BAD_ACCESS);
54         RS_EGL_ERR_CASE_STR(EGL_BAD_ALLOC);
55         RS_EGL_ERR_CASE_STR(EGL_BAD_ATTRIBUTE);
56         RS_EGL_ERR_CASE_STR(EGL_BAD_CONFIG);
57         RS_EGL_ERR_CASE_STR(EGL_BAD_CONTEXT);
58         RS_EGL_ERR_CASE_STR(EGL_BAD_CURRENT_SURFACE);
59         RS_EGL_ERR_CASE_STR(EGL_BAD_DISPLAY);
60         RS_EGL_ERR_CASE_STR(EGL_BAD_MATCH);
61         RS_EGL_ERR_CASE_STR(EGL_BAD_NATIVE_PIXMAP);
62         RS_EGL_ERR_CASE_STR(EGL_BAD_NATIVE_WINDOW);
63         RS_EGL_ERR_CASE_STR(EGL_BAD_PARAMETER);
64         RS_EGL_ERR_CASE_STR(EGL_BAD_SURFACE);
65         RS_EGL_ERR_CASE_STR(EGL_CONTEXT_LOST);
66         default: return "Unknown";
67     }
68 }
69 
GetEGLCreateImageKHRFunc()70 static PFNEGLCREATEIMAGEKHRPROC GetEGLCreateImageKHRFunc()
71 {
72     static auto func = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
73     return func;
74 }
75 
GetEGLDestroyImageKHRFunc()76 static PFNEGLDESTROYIMAGEKHRPROC GetEGLDestroyImageKHRFunc()
77 {
78     static auto func = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
79     return func;
80 }
81 
GetGLEGLImageTargetTexture2DOESFunc()82 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC GetGLEGLImageTargetTexture2DOESFunc()
83 {
84     static auto func = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(
85         eglGetProcAddress("glEGLImageTargetTexture2DOES"));
86     return func;
87 }
88 
89 // RAII object for NativeWindowBuffer
90 class NativeWindowBufferObject {
91 public:
NativeWindowBufferObject(sptr<OHOS::SurfaceBuffer> buffer)92     explicit NativeWindowBufferObject(sptr<OHOS::SurfaceBuffer> buffer)
93         : handle_(CreateNativeWindowBufferFromSurfaceBuffer(&buffer))
94     {
95     }
NativeWindowBufferObject(NativeWindowBuffer * nativeBuffer)96     explicit NativeWindowBufferObject(NativeWindowBuffer* nativeBuffer)
97         : handle_(nativeBuffer)
98     {
99     }
100 
~NativeWindowBufferObject()101     ~NativeWindowBufferObject() noexcept
102     {
103         if (handle_ != nullptr) {
104             DestroyNativeWindowBuffer(handle_);
105         }
106     }
107 
108     NativeWindowBufferObject(const NativeWindowBufferObject&) = delete;
109     void operator=(const NativeWindowBufferObject&) = delete;
110 
operator ==(std::nullptr_t) const111     bool operator==(std::nullptr_t) const
112     {
113         return handle_ == nullptr;
114     }
operator !=(std::nullptr_t) const115     bool operator!=(std::nullptr_t) const
116     {
117         return handle_ != nullptr;
118     }
119 
120     // not explicit so you can use it to do the implicit-cast.
121     // you should not delete or call DestroyNativeWindowBuffer for this pointer.
operator NativeWindowBuffer*() const122     operator NativeWindowBuffer* () const
123     {
124         return Get();
125     }
126     // you should not delete or call DestroyNativeWindowBuffer for this pointer.
Get() const127     NativeWindowBuffer* Get() const
128     {
129         return handle_;
130     }
131 
Release()132     NativeWindowBuffer* Release()
133     {
134         NativeWindowBuffer* out = handle_;
135         handle_ = nullptr;
136         return out;
137     }
138 
139 private:
140     NativeWindowBuffer* handle_ = nullptr;
141 };
142 
CreateNativeWindowBuffer(const sptr<OHOS::SurfaceBuffer> & buffer)143 NativeWindowBufferObject CreateNativeWindowBuffer(const sptr<OHOS::SurfaceBuffer>& buffer)
144 {
145     return NativeWindowBufferObject(buffer);
146 }
147 
CastToEGLClientBuffer(NativeWindowBuffer * nativeBuffer)148 EGLClientBuffer CastToEGLClientBuffer(NativeWindowBuffer* nativeBuffer)
149 {
150     return static_cast<EGLClientBuffer>(nativeBuffer);
151 }
152 
CastFromEGLClientBuffer(EGLClientBuffer eglClientBuffer)153 NativeWindowBuffer* CastFromEGLClientBuffer(EGLClientBuffer eglClientBuffer)
154 {
155     return static_cast<NativeWindowBuffer*>(eglClientBuffer);
156 }
157 
CreateEGLImage(EGLDisplay eglDisplay,EGLContext eglContext,const NativeWindowBufferObject & nativeBuffer)158 EGLImageKHR CreateEGLImage(
159     EGLDisplay eglDisplay,
160     EGLContext eglContext,
161     const NativeWindowBufferObject& nativeBuffer)
162 {
163     EGLint attrs[] = {
164         EGL_IMAGE_PRESERVED_KHR,
165         EGL_TRUE,
166         EGL_NONE,
167     };
168 
169     return GetEGLCreateImageKHRFunc()(
170         eglDisplay, eglContext, EGL_NATIVE_BUFFER_OHOS, CastToEGLClientBuffer(nativeBuffer), attrs);
171 }
172 } // namespace Detail
173 
~EglImageResource()174 EglImageResource::~EglImageResource() noexcept
175 {
176     if (eglImage_ != EGL_NO_IMAGE_KHR) {
177         Detail::GetEGLDestroyImageKHRFunc()(eglDisplay_, eglImage_);
178         eglImage_ = EGL_NO_IMAGE_KHR;
179     }
180 
181     if (textureId_ != 0) {
182         glDeleteTextures(1, &textureId_);
183         textureId_ = 0;
184     }
185 
186     // auto dec ref.
187     Detail::NativeWindowBufferObject nBufferDecRef(
188         Detail::CastFromEGLClientBuffer(eglClientBuffer_));
189 }
190 
BindToTexture()191 bool EglImageResource::BindToTexture()
192 {
193     // no image check.
194     if (eglImage_ == EGL_NO_IMAGE_KHR) {
195         RS_LOGE("EglImageResource::BindToTexture: eglImage_ is null.");
196         return false;
197     }
198 
199     glGenTextures(1, &textureId_);
200     if (textureId_ == 0) {
201         RS_LOGE("EglImageResource::BindToTexture: glGenTextures error.");
202         return false;
203     }
204 
205     // bind this eglImage_ to textureId_.
206     glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId_);
207     Detail::GetGLEGLImageTargetTexture2DOESFunc()(GL_TEXTURE_EXTERNAL_OES, eglImage_);
208     return true;
209 }
210 
Create(EGLDisplay eglDisplay,EGLContext eglContext,const sptr<OHOS::SurfaceBuffer> & buffer)211 std::unique_ptr<EglImageResource> EglImageResource::Create(
212     EGLDisplay eglDisplay,
213     EGLContext eglContext,
214     const sptr<OHOS::SurfaceBuffer>& buffer)
215 {
216     auto nativeBuffer = Detail::CreateNativeWindowBuffer(buffer);
217     if (nativeBuffer == nullptr) {
218         return nullptr;
219     }
220 
221     EGLImageKHR img = Detail::CreateEGLImage(eglDisplay, eglContext, nativeBuffer);
222     if (img == EGL_NO_IMAGE_KHR) {
223         RS_LOGE("EglImageResource::Create: eglCreateImageKHR failed, error %{public}s.",
224             Detail::EGLErrorString(eglGetError()));
225         return nullptr;
226     }
227 
228     auto imageCache = std::make_unique<EglImageResource>(
229         eglDisplay, img, Detail::CastToEGLClientBuffer(nativeBuffer.Release()));
230     if (!imageCache->BindToTexture()) {
231         return nullptr;
232     }
233     return imageCache;
234 }
235 
WaitAcquireFence(const sptr<SyncFence> & acquireFence)236 void RSEglImageManager::WaitAcquireFence(const sptr<SyncFence>& acquireFence)
237 {
238     if (acquireFence == nullptr) {
239         return;
240     }
241     acquireFence->Wait(3000); // 3000ms
242 }
243 
CreateEglImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const pid_t threadIndex)244 GLuint RSEglImageManager::CreateEglImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer>& buffer,
245     const pid_t threadIndex)
246 {
247     auto bufferId = buffer->GetSeqNum();
248     auto imageCache = EglImageResource::Create(eglDisplay_, EGL_NO_CONTEXT, buffer);
249     if (imageCache == nullptr) {
250         RS_LOGE("RSEglImageManager::CreateEglImageCacheFromBuffer:failed to create for buffer id %{public}d.",
251             bufferId);
252         return 0; // return texture id 0.
253     }
254     imageCache->SetThreadIndex(threadIndex);
255     auto textureId = imageCache->GetTextureId();
256     {
257         std::lock_guard<std::mutex> lock(opMutex_);
258         imageCacheSeqs_[bufferId] = std::move(imageCache);
259     }
260     cacheQueue_.push(bufferId);
261     return textureId;
262 }
263 
MapEglImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex)264 GLuint RSEglImageManager::MapEglImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer>& buffer,
265     const sptr<SyncFence>& acquireFence, pid_t threadIndex)
266 {
267     WaitAcquireFence(acquireFence);
268     if (buffer == nullptr) {
269         RS_LOGE("RSEglImageManager::MapEglImageFromSurfaceBuffer: buffer is null.");
270         return 0;
271     }
272     auto bufferId = buffer->GetSeqNum();
273     RS_OPTIONAL_TRACE_NAME_FMT("MapEglImage seqNum: %d", bufferId);
274     RS_LOGD("RSEglImageManager::MapEglImageFromSurfaceBuffer: %{public}d", bufferId);
275     {
276         bool isImageCacheNotFound = false;
277         std::lock_guard<std::mutex> lock(opMutex_);
278         isImageCacheNotFound = imageCacheSeqs_.count(bufferId) == 0 || imageCacheSeqs_[bufferId] == nullptr;
279         if (!isImageCacheNotFound) {
280             const auto& imageCache = imageCacheSeqs_[bufferId];
281             return imageCache->GetTextureId();
282         }
283     }
284     // cache not found, create it.
285     return CreateEglImageCacheFromBuffer(buffer, threadIndex);
286 }
287 
ShrinkCachesIfNeeded(bool isForUniRedraw)288 void RSEglImageManager::ShrinkCachesIfNeeded(bool isForUniRedraw)
289 {
290     while (cacheQueue_.size() > MAX_CACHE_SIZE) {
291         const int32_t id = cacheQueue_.front();
292         if (isForUniRedraw) {
293             UnMapEglImageFromSurfaceBufferForUniRedraw(id);
294         } else {
295             UnMapImageFromSurfaceBuffer(id);
296         }
297         cacheQueue_.pop();
298     }
299 }
300 
UnMapImageFromSurfaceBuffer(int32_t seqNum)301 void RSEglImageManager::UnMapImageFromSurfaceBuffer(int32_t seqNum)
302 {
303     pid_t threadIndex = 0;
304     {
305         std::lock_guard<std::mutex> lock(opMutex_);
306         if (imageCacheSeqs_.count(seqNum) == 0) {
307             return;
308         }
309         if (imageCacheSeqs_[seqNum]) {
310             threadIndex = imageCacheSeqs_[seqNum]->GetThreadIndex();
311         }
312     }
313     auto func = [this, seqNum]() {
314         std::unique_ptr<EglImageResource> imageCacheSeq;
315         {
316             std::lock_guard<std::mutex> lock(opMutex_);
317             if (imageCacheSeqs_.count(seqNum) == 0) {
318                 return;
319             }
320             imageCacheSeq = std::move(imageCacheSeqs_[seqNum]);
321         }
322         imageCacheSeq.reset();
323         RS_OPTIONAL_TRACE_NAME_FMT("UnmapEglImage seqNum: %d", seqNum);
324         RS_LOGD("RSEglImageManager::UnMapEglImageFromSurfaceBuffer: %{public}d", seqNum);
325     };
326     RSTaskDispatcher::GetInstance().PostTask(threadIndex, func);
327 }
328 
UnMapEglImageFromSurfaceBufferForUniRedraw(int32_t seqNum)329 void RSEglImageManager::UnMapEglImageFromSurfaceBufferForUniRedraw(int32_t seqNum)
330 {
331     RSHardwareThread::Instance().PostTask([this, seqNum]() {
332         std::lock_guard<std::mutex> lock(opMutex_);
333         if (imageCacheSeqs_.count(seqNum) == 0) {
334             return;
335         }
336         (void)imageCacheSeqs_.erase(seqNum);
337         RS_LOGD("RSEglImageManager::UnMapEglImageFromSurfaceBufferForRedraw");
338     });
339 }
340 
CreateImageFromBuffer(RSPaintFilterCanvas & canvas,const BufferDrawParam & params,const std::shared_ptr<Drawing::ColorSpace> & drawingColorSpace)341 std::shared_ptr<Drawing::Image> RSEglImageManager::CreateImageFromBuffer(
342     RSPaintFilterCanvas& canvas, const BufferDrawParam& params,
343     const std::shared_ptr<Drawing::ColorSpace>& drawingColorSpace)
344 {
345     const sptr<SurfaceBuffer>& buffer = params.buffer;
346     const sptr<SyncFence>& acquireFence = params.acquireFence;
347     const pid_t threadIndex = params.threadIndex;
348     const Drawing::AlphaType alphaType = params.alphaType;
349 
350 #if defined(RS_ENABLE_EGLIMAGE) && defined(RS_ENABLE_GL)
351     if (canvas.GetGPUContext() == nullptr) {
352         RS_LOGE("RSEglImageManager::CreateEglImageFromBuffer GrContext is null!");
353         return nullptr;
354     }
355     if (buffer == nullptr) {
356         RS_LOGE("RSEglImageManager::CreateEglImageFromBuffer buffer is null!");
357         return nullptr;
358     }
359     auto eglTextureId = MapEglImageFromSurfaceBuffer(buffer, acquireFence, threadIndex);
360     if (eglTextureId == 0) {
361         RS_LOGE("RSEglImageManager::CreateEglImageFromBuffer MapEglImageFromSurfaceBuffer return invalid texture ID");
362         return nullptr;
363     }
364     auto pixelFmt = buffer->GetFormat();
365     auto bitmapFormat = RSBaseRenderUtil::GenerateDrawingBitmapFormat(buffer, alphaType);
366 
367     auto image = std::make_shared<Drawing::Image>();
368     Drawing::TextureInfo externalTextureInfo;
369     externalTextureInfo.SetWidth(buffer->GetSurfaceBufferWidth());
370     externalTextureInfo.SetHeight(buffer->GetSurfaceBufferHeight());
371 
372     auto surfaceOrigin = Drawing::TextureOrigin::TOP_LEFT;
373     externalTextureInfo.SetIsMipMapped(false);
374     externalTextureInfo.SetTarget(GL_TEXTURE_EXTERNAL_OES);
375     externalTextureInfo.SetID(eglTextureId);
376     auto glType = GR_GL_RGBA8;
377     if (pixelFmt == GRAPHIC_PIXEL_FMT_BGRA_8888) {
378         glType = GR_GL_BGRA8;
379     } else if (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010 ||
380         pixelFmt == GRAPHIC_PIXEL_FMT_RGBA_1010102) {
381         glType = GR_GL_RGB10_A2;
382     }
383     externalTextureInfo.SetFormat(glType);
384     if (!image->BuildFromTexture(*canvas.GetGPUContext(), externalTextureInfo,
385         surfaceOrigin, bitmapFormat, drawingColorSpace)) {
386         RS_LOGE("RSEglImageManager::CreateEglImageFromBuffer image BuildFromTexture failed");
387         return nullptr;
388     }
389     return image;
390 #else
391     return nullptr;
392 #endif // RS_ENABLE_EGLIMAGE
393 }
394 
GetIntersectImage(Drawing::RectI & imgCutRect,const std::shared_ptr<Drawing::GPUContext> & context,const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex)395 std::shared_ptr<Drawing::Image> RSEglImageManager::GetIntersectImage(Drawing::RectI& imgCutRect,
396     const std::shared_ptr<Drawing::GPUContext>& context, const sptr<OHOS::SurfaceBuffer>& buffer,
397     const sptr<SyncFence>& acquireFence, pid_t threadIndex)
398 {
399     auto eglTextureId = MapEglImageFromSurfaceBuffer(buffer, acquireFence, threadIndex);
400     if (eglTextureId == 0) {
401         RS_LOGE("RSEglImageManager::GetIntersectImageFromGL invalid texture ID");
402         return nullptr;
403     }
404 
405     Drawing::BitmapFormat bitmapFormat = RSBaseRenderUtil::GenerateDrawingBitmapFormat(buffer);
406     Drawing::TextureInfo externalTextureInfo;
407     externalTextureInfo.SetWidth(buffer->GetSurfaceBufferWidth());
408     externalTextureInfo.SetHeight(buffer->GetSurfaceBufferHeight());
409     externalTextureInfo.SetIsMipMapped(false);
410     externalTextureInfo.SetTarget(GL_TEXTURE_EXTERNAL_OES);
411     externalTextureInfo.SetID(eglTextureId);
412     auto glType = GR_GL_RGBA8;
413     auto pixelFmt = buffer->GetFormat();
414     if (pixelFmt == GRAPHIC_PIXEL_FMT_BGRA_8888) {
415         glType = GR_GL_BGRA8;
416     } else if (pixelFmt == GRAPHIC_PIXEL_FMT_YCBCR_P010 || pixelFmt == GRAPHIC_PIXEL_FMT_YCRCB_P010) {
417         glType = GL_RGB10_A2;
418     }
419     externalTextureInfo.SetFormat(glType);
420 
421     std::shared_ptr<Drawing::Image> layerImage = std::make_shared<Drawing::Image>();
422     if (!layerImage->BuildFromTexture(*context, externalTextureInfo,
423         Drawing::TextureOrigin::TOP_LEFT, bitmapFormat, nullptr)) {
424         RS_LOGE("RSEglImageManager::GetIntersectImageFromGL image BuildFromTexture failed");
425         return nullptr;
426     }
427 
428     std::shared_ptr<Drawing::Image> cutDownImage = std::make_shared<Drawing::Image>();
429     bool res = cutDownImage->BuildSubset(layerImage, imgCutRect, *context);
430     if (!res) {
431         ROSEN_LOGE("RSEglImageManager::GetIntersectImageFromGL cutDownImage BuildSubset failed.");
432         return nullptr;
433     }
434     Drawing::ImageInfo info = Drawing::ImageInfo(imgCutRect.GetWidth(), imgCutRect.GetHeight(),
435         Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL);
436 
437     std::shared_ptr<Drawing::Surface> surface = Drawing::Surface::MakeRenderTarget(context.get(), false, info);
438     if (surface == nullptr) {
439         RS_LOGE("RSEglImageManager::GetIntersectImageFromGL MakeRenderTarget failed.");
440         return nullptr;
441     }
442     auto drawCanvas = std::make_shared<RSPaintFilterCanvas>(surface.get());
443     drawCanvas->DrawImage(*cutDownImage, 0.f, 0.f, Drawing::SamplingOptions());
444     surface->FlushAndSubmit(true);
445     return surface.get()->GetImageSnapshot();
446 }
447 } // namespace Rosen
448 } // namespace OHOS
449