• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "render_context.h"
17 
18 #include <sstream>
19 #include <string>
20 
21 #include "EGL/egl.h"
22 #include "rs_trace.h"
23 #include "window.h"
24 
25 
26 #include "memory/rs_tag_tracker.h"
27 
28 #include "utils/log.h"
29 
30 namespace OHOS {
31 namespace Rosen {
32 using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
33 constexpr const char* EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
34 constexpr const char* EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
35 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
36 constexpr char CHARACTER_WHITESPACE = ' ';
37 constexpr const char* CHARACTER_STRING_WHITESPACE = " ";
38 constexpr const char* EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
39 constexpr const char* EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
40 
41 // use functor to call gel*KHR API
GetEGLSetDamageRegionKHRFunc()42 static PFNEGLSETDAMAGEREGIONKHRPROC GetEGLSetDamageRegionKHRFunc()
43 {
44     static auto func = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(eglGetProcAddress("eglSetDamageRegionKHR"));
45     return func;
46 }
47 
CheckEglExtension(const char * extensions,const char * extension)48 static bool CheckEglExtension(const char* extensions, const char* extension)
49 {
50     size_t extlen = strlen(extension);
51     const char* end = extensions + strlen(extensions);
52 
53     while (extensions < end) {
54         size_t n = 0;
55         /* Skip whitespaces, if any */
56         if (*extensions == CHARACTER_WHITESPACE) {
57             extensions++;
58             continue;
59         }
60 
61         n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
62 
63         /* Compare strings */
64         if (n == extlen && strncmp(extension, extensions, n) == 0) {
65             return true; /* Found */
66         }
67         extensions += n;
68     }
69     /* Not found */
70     return false;
71 }
72 
GetPlatformEglDisplay(EGLenum platform,void * native_display,const EGLint * attrib_list)73 static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void* native_display, const EGLint* attrib_list)
74 {
75     static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
76 
77     if (!eglGetPlatformDisplayExt) {
78         const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
79         if (extensions &&
80             (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
81                 CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
82             eglGetPlatformDisplayExt = reinterpret_cast<GetPlatformDisplayExt>(
83                 eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT));
84         }
85     }
86 
87     if (eglGetPlatformDisplayExt) {
88         return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
89     }
90 
91     return eglGetDisplay(static_cast<EGLNativeDisplayType>(native_display));
92 }
93 
RenderContext()94 RenderContext::RenderContext()
95 #ifndef USE_ROSEN_DRAWING
96     : grContext_(nullptr),
97       skSurface_(nullptr),
98 #else
99     : drGPUContext_(nullptr),
100       surface_(nullptr),
101 #endif
102       nativeWindow_(nullptr),
103       eglDisplay_(EGL_NO_DISPLAY),
104       eglContext_(EGL_NO_CONTEXT),
105       eglSurface_(EGL_NO_SURFACE),
106       config_(nullptr),
107       mHandler_(nullptr)
108 {}
109 
~RenderContext()110 RenderContext::~RenderContext()
111 {
112     if (eglDisplay_ == EGL_NO_DISPLAY) {
113         return;
114     }
115 
116     eglDestroyContext(eglDisplay_, eglContext_);
117     if (pbufferSurface_ != EGL_NO_SURFACE) {
118         eglDestroySurface(eglDisplay_, pbufferSurface_);
119     }
120     eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
121     eglTerminate(eglDisplay_);
122     eglReleaseThread();
123 
124     eglDisplay_ = EGL_NO_DISPLAY;
125     eglContext_ = EGL_NO_CONTEXT;
126     eglSurface_ = EGL_NO_SURFACE;
127     pbufferSurface_ = EGL_NO_SURFACE;
128 #ifndef USE_ROSEN_DRAWING
129     grContext_ = nullptr;
130     skSurface_ = nullptr;
131 #else
132     drGPUContext_ = nullptr;
133     surface_ = nullptr;
134 #endif
135     mHandler_ = nullptr;
136 }
137 
CreatePbufferSurface()138 void RenderContext::CreatePbufferSurface()
139 {
140     const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
141 
142     if ((extensions != nullptr) &&
143        (!CheckEglExtension(extensions, EGL_KHR_SURFACELESS_CONTEXT)) &&
144        (pbufferSurface_ == EGL_NO_SURFACE)) {
145         EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
146         pbufferSurface_ = eglCreatePbufferSurface(eglDisplay_, config_, attribs);
147         if (pbufferSurface_ == EGL_NO_SURFACE) {
148             LOGE("Failed to create pbuffer surface");
149             return;
150         }
151     }
152 }
153 
InitializeEglContext()154 void RenderContext::InitializeEglContext()
155 {
156     if (IsEglContextReady()) {
157         return;
158     }
159 
160     LOGD("Creating EGLContext!!!");
161     eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
162     if (eglDisplay_ == EGL_NO_DISPLAY) {
163         LOGW("Failed to create EGLDisplay gl errno : %{public}x", eglGetError());
164         return;
165     }
166 
167     EGLint major, minor;
168     if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
169         LOGE("Failed to initialize EGLDisplay");
170         return;
171     }
172 
173     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
174         LOGE("Failed to bind OpenGL ES API");
175         return;
176     }
177 
178     unsigned int ret;
179     EGLint count;
180     EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
181         EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
182 
183     ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
184     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
185         LOGE("Failed to eglChooseConfig");
186         return;
187     }
188 
189     static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE };
190 
191     eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
192     if (eglContext_ == EGL_NO_CONTEXT) {
193         LOGE("Failed to create egl context %{public}x", eglGetError());
194         return;
195     }
196     CreatePbufferSurface();
197     if (!eglMakeCurrent(eglDisplay_, pbufferSurface_, pbufferSurface_, eglContext_)) {
198         LOGE("Failed to make current on surface, error is %{public}x", eglGetError());
199         return;
200     }
201 
202     LOGD("Create EGL context successfully, version %{public}d.%{public}d", major, minor);
203 }
204 
MakeCurrent(EGLSurface surface,EGLContext context)205 void RenderContext::MakeCurrent(EGLSurface surface, EGLContext context)
206 {
207     if (surface == EGL_NO_SURFACE) {
208         surface = pbufferSurface_;
209     }
210     if (context == EGL_NO_CONTEXT) {
211         context = eglContext_;
212     }
213     if (!eglMakeCurrent(eglDisplay_, surface, surface, context)) {
214         LOGE("Failed to make current on surface, error is %{public}x", eglGetError());
215     }
216     eglSurface_ = surface;
217 }
218 
ShareMakeCurrent(EGLContext shareContext)219 void RenderContext::ShareMakeCurrent(EGLContext shareContext)
220 {
221     eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, shareContext);
222 }
223 
ShareMakeCurrentNoSurface(EGLContext shareContext)224 void RenderContext::ShareMakeCurrentNoSurface(EGLContext shareContext)
225 {
226     eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, shareContext);
227 }
228 
MakeSelfCurrent()229 void RenderContext::MakeSelfCurrent()
230 {
231     eglMakeCurrent(eglDisplay_, eglSurface_, eglSurface_, eglContext_);
232 }
233 
CreateShareContext()234 EGLContext RenderContext::CreateShareContext()
235 {
236     std::unique_lock<std::mutex> lock(shareContextMutex_);
237     static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE};
238     auto eglShareContext = eglCreateContext(eglDisplay_, config_, eglContext_, context_attribs);
239     return eglShareContext;
240 }
241 
SwapBuffers(EGLSurface surface) const242 void RenderContext::SwapBuffers(EGLSurface surface) const
243 {
244     RS_TRACE_FUNC();
245     if (!eglSwapBuffers(eglDisplay_, surface)) {
246         LOGE("Failed to SwapBuffers on surface, error is %{public}x", eglGetError());
247     } else {
248         LOGD("SwapBuffers successfully");
249     }
250 }
251 
DestroyEGLSurface(EGLSurface surface)252 void RenderContext::DestroyEGLSurface(EGLSurface surface)
253 {
254     if (!eglDestroySurface(eglDisplay_, surface)) {
255         LOGE("Failed to DestroyEGLSurface surface, error is %{public}x", eglGetError());
256     }
257 }
258 
CreateEGLSurface(EGLNativeWindowType eglNativeWindow)259 EGLSurface RenderContext::CreateEGLSurface(EGLNativeWindowType eglNativeWindow)
260 {
261     if (!IsEglContextReady()) {
262         LOGE("EGL context has not initialized");
263         return EGL_NO_SURFACE;
264     }
265     nativeWindow_ = eglNativeWindow;
266 
267     eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
268 
269     EGLSurface surface = eglCreateWindowSurface(eglDisplay_, config_, nativeWindow_, NULL);
270     if (surface == EGL_NO_SURFACE) {
271         LOGW("Failed to create eglsurface!!! %{public}x", eglGetError());
272         return EGL_NO_SURFACE;
273     }
274 
275     LOGD("CreateEGLSurface");
276 
277     eglSurface_ = surface;
278     return surface;
279 }
280 
SetColorSpace(GraphicColorGamut colorSpace)281 void RenderContext::SetColorSpace(GraphicColorGamut colorSpace)
282 {
283     colorSpace_ = colorSpace;
284 }
285 
286 #ifndef USE_ROSEN_DRAWING
SetUpGrContext()287 bool RenderContext::SetUpGrContext()
288 {
289     if (grContext_ != nullptr) {
290         LOGD("grContext has already created!!");
291         return true;
292     }
293 
294     sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
295     if (glInterface.get() == nullptr) {
296         LOGE("SetUpGrContext failed to make native interface");
297         return false;
298     }
299 
300     GrContextOptions options;
301     options.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
302     options.fPreferExternalImagesOverES3 = true;
303     options.fDisableDistanceFieldPaths = true;
304 
305     mHandler_ = std::make_shared<MemoryHandler>();
306     auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
307     auto size = glesVersion ? strlen(glesVersion) : 0;
308     if (isUniRenderMode_) {
309         cacheDir_ = UNIRENDER_CACHE_DIR;
310     }
311     mHandler_->ConfigureContext(&options, glesVersion, size, cacheDir_, isUniRenderMode_);
312 
313 #if defined(NEW_SKIA)
314     sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
315 #else
316     sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
317 #endif
318     if (grContext == nullptr) {
319         LOGE("SetUpGrContext grContext is null");
320         return false;
321     }
322     grContext_ = std::move(grContext);
323     return true;
324 }
325 #else
SetUpGpuContext()326 bool RenderContext::SetUpGpuContext()
327 {
328     if (drGPUContext_ != nullptr) {
329         LOGD("Drawing GPUContext has already created!!");
330         return true;
331     }
332     mHandler_ = std::make_shared<MemoryHandler>();
333     auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
334     if (isUniRenderMode_) {
335         cacheDir_ = UNIRENDER_CACHE_DIR;
336     }
337     Drawing::GPUContextOptions options;
338     auto size = glesVersion ? strlen(glesVersion) : 0;
339     mHandler_->ConfigureContext(&options, glesVersion, size, cacheDir_, isUniRenderMode_);
340 
341     auto drGPUContext = std::make_shared<Drawing::GPUContext>();
342     if (!drGPUContext->BuildFromGL(options)) {
343         LOGE("SetUpGrContext drGPUContext is null");
344         return false;
345     }
346     drGPUContext_ = std::move(drGPUContext);
347     return true;
348 }
349 #endif
350 
351 #ifndef USE_ROSEN_DRAWING
AcquireSurface(int width,int height)352 sk_sp<SkSurface> RenderContext::AcquireSurface(int width, int height)
353 {
354     if (!SetUpGrContext()) {
355         LOGE("GrContext is not ready!!!");
356         return nullptr;
357     }
358 
359     GrGLFramebufferInfo framebufferInfo;
360     framebufferInfo.fFBOID = 0;
361     framebufferInfo.fFormat = GL_RGBA8;
362 
363     SkColorType colorType = kRGBA_8888_SkColorType;
364 
365     GrBackendRenderTarget backendRenderTarget(width, height, 0, 8, framebufferInfo);
366 #if defined(NEW_SKIA)
367     SkSurfaceProps surfaceProps(0, kRGB_H_SkPixelGeometry);
368 #else
369     SkSurfaceProps surfaceProps = SkSurfaceProps::kLegacyFontHost_InitType;
370 #endif
371 
372     sk_sp<SkColorSpace> skColorSpace = nullptr;
373 
374     switch (colorSpace_) {
375         // [planning] in order to stay consistant with the colorspace used before, we disabled
376         // GRAPHIC_COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
377         case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
378 #if defined(NEW_SKIA)
379             skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
380 #else
381             skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
382 #endif
383             break;
384         case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
385             skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB);
386             break;
387         case GRAPHIC_COLOR_GAMUT_BT2020:
388             skColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020);
389             break;
390         default:
391             break;
392     }
393 
394     RSTagTracker tagTracker(GetGrContext(), RSTagTracker::TAGTYPE::TAG_ACQUIRE_SURFACE);
395 
396     skSurface_ = SkSurface::MakeFromBackendRenderTarget(
397         GetGrContext(), backendRenderTarget, kBottomLeft_GrSurfaceOrigin, colorType, skColorSpace, &surfaceProps);
398     if (skSurface_ == nullptr) {
399         LOGW("skSurface is nullptr");
400         return nullptr;
401     }
402 
403     LOGD("CreateCanvas successfully!!!");
404     return skSurface_;
405 }
406 #else
AcquireSurface(int width,int height)407 std::shared_ptr<Drawing::Surface> RenderContext::AcquireSurface(int width, int height)
408 {
409     if (!SetUpGpuContext()) {
410         LOGE("GrContext is not ready!!!");
411         return nullptr;
412     }
413 
414     std::shared_ptr<Drawing::ColorSpace> colorSpace = nullptr;
415 
416     switch (colorSpace_) {
417         // [planning] in order to stay consistant with the colorspace used before, we disabled
418         // COLOR_GAMUT_SRGB to let the branch to default, then skColorSpace is set to nullptr
419         case GRAPHIC_COLOR_GAMUT_DISPLAY_P3:
420             colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
421                 Drawing::CMSMatrixType::DCIP3);
422             break;
423         case GRAPHIC_COLOR_GAMUT_ADOBE_RGB:
424             colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
425                 Drawing::CMSMatrixType::ADOBE_RGB);
426             break;
427         case GRAPHIC_COLOR_GAMUT_BT2020:
428             colorSpace = Drawing::ColorSpace::CreateRGB(Drawing::CMSTransferFuncType::SRGB,
429                 Drawing::CMSMatrixType::REC2020);
430             break;
431         default:
432             break;
433     }
434 
435     struct Drawing::FrameBuffer bufferInfo;
436     bufferInfo.width = width;
437     bufferInfo.height = height;
438     bufferInfo.FBOID = 0;
439     bufferInfo.Format = GL_RGBA8;
440     bufferInfo.gpuContext = drGPUContext_;
441     bufferInfo.colorSpace = colorSpace;
442 
443     surface_ = std::make_shared<Drawing::Surface>();
444     if (!surface_->Bind(bufferInfo)) {
445         LOGW("surface_ is nullptr");
446         surface_ = nullptr;
447         return nullptr;
448     }
449 
450     LOGD("CreateCanvas successfully!!!");
451     return surface_;
452 }
453 #endif
454 
RenderFrame()455 void RenderContext::RenderFrame()
456 {
457     RS_TRACE_FUNC();
458     // flush commands
459 #ifndef USE_ROSEN_DRAWING
460     if (skSurface_->getCanvas() != nullptr) {
461         LOGD("RenderFrame: Canvas");
462         RSTagTracker tagTracker(GetGrContext(), RSTagTracker::TAGTYPE::TAG_RENDER_FRAME);
463         skSurface_->getCanvas()->flush();
464 #else
465     if (surface_ != nullptr && surface_->GetCanvas() != nullptr) {
466         LOGD("RenderFrame: Canvas");
467         surface_->GetCanvas()->Flush();
468 #endif
469     } else {
470         LOGW("canvas is nullptr!!!");
471     }
472 }
473 
474 EGLint RenderContext::QueryEglBufferAge()
475 {
476     if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
477         LOGE("eglDisplay or eglSurface is nullptr");
478         return EGL_UNKNOWN;
479     }
480     EGLint bufferAge = EGL_UNKNOWN;
481     EGLBoolean ret = eglQuerySurface(eglDisplay_, eglSurface_, EGL_BUFFER_AGE_KHR, &bufferAge);
482     if (ret == EGL_FALSE) {
483         LOGE("eglQuerySurface is failed");
484         return EGL_UNKNOWN;
485     }
486     return bufferAge;
487 }
488 
489 void RenderContext::DamageFrame(int32_t left, int32_t top, int32_t width, int32_t height)
490 {
491     if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
492         LOGE("eglDisplay or eglSurface is nullptr");
493         return;
494     }
495     RS_TRACE_FUNC();
496 
497     EGLint rect[4];
498     rect[0] = left;
499     rect[1] = top;
500     rect[2] = width;
501     rect[3] = height;
502 
503     EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, rect, 1);
504     if (ret == EGL_FALSE) {
505         LOGE("eglSetDamageRegionKHR is failed");
506     }
507 }
508 
509 void RenderContext::DamageFrame(const std::vector<RectI> &rects)
510 {
511     if ((eglDisplay_ == nullptr) || (eglSurface_ == nullptr)) {
512         LOGE("eglDisplay or eglSurface is nullptr");
513         return;
514     }
515     RS_TRACE_FUNC();
516 
517     size_t size = rects.size();
518     if (size == 0) {
519         LOGD("invalid rects size");
520         return;
521     }
522 
523     EGLint eglRect[size * 4]; // 4 is size of RectI.
524     int index = 0;
525     for (const RectI& rect : rects) {
526         eglRect[index * 4] = rect.left_; // 4 is size of RectI.
527         eglRect[index * 4 + 1] = rect.top_; // 4 is size of RectI.
528         eglRect[index * 4 + 2] = rect.width_; // 4 is size of RectI, 2 is the index of the width_ subscript.
529         eglRect[index * 4 + 3] = rect.height_; // 4 is size of RectI, 3 is the index of the height_ subscript.
530         index++;
531     }
532 
533     EGLBoolean ret = GetEGLSetDamageRegionKHRFunc()(eglDisplay_, eglSurface_, eglRect, size);
534     if (ret == EGL_FALSE) {
535         LOGE("eglSetDamageRegionKHR is failed");
536     }
537 }
538 
539 void RenderContext::ClearRedundantResources()
540 {
541     RS_TRACE_FUNC();
542 #ifndef USE_ROSEN_DRAWING
543     if (grContext_ != nullptr) {
544         LOGD("grContext clear redundant resources");
545         grContext_->flush();
546         // GPU resources that haven't been used in the past 10 seconds
547         grContext_->purgeResourcesNotUsedInMs(std::chrono::seconds(10));
548     }
549 #else
550     if (drGPUContext_ != nullptr) {
551         LOGD("grContext clear redundant resources");
552         drGPUContext_->Flush();
553         // GPU resources that haven't been used in the past 10 seconds
554         drGPUContext_->PerformDeferredCleanup(std::chrono::seconds(10));
555     }
556 #endif
557 }
558 
559 RenderContextFactory& RenderContextFactory::GetInstance()
560 {
561     static RenderContextFactory rf;
562     return rf;
563 }
564 } // namespace Rosen
565 } // namespace OHOS
566