1 /*
2  * Copyright (C) 2023 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 "image_log.h"
19 
20 #undef LOG_DOMAIN
21 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
22 
23 #undef LOG_TAG
24 #define LOG_TAG "PixelMap"
25 
26 namespace OHOS {
27 namespace Media {
28 
RenderContext()29 RenderContext::RenderContext()
30 {}
31 
~RenderContext()32 RenderContext::~RenderContext() noexcept
33 {
34     Clear();
35 }
36 
Init()37 bool RenderContext::Init()
38 {
39     if (!InitEGLContext()) {
40         return false;
41     }
42 
43     if (!InitGrContext()) {
44         return false;
45     }
46 
47     return true;
48 }
49 
InitEGLContext()50 bool RenderContext::InitEGLContext()
51 {
52     eglDisplay_ = eglGetPlatformDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, nullptr);
53     if (eglDisplay_ == EGL_NO_DISPLAY) {
54         IMAGE_LOGE("RenderContext::Init: eglGetDisplay error: ");
55         return false;
56     }
57 
58     EGLint major = 0;
59     EGLint minor = 0;
60     if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
61         IMAGE_LOGE("Failed to initialize EGLDisplay");
62         return false;
63     }
64 
65     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
66         IMAGE_LOGE("Failed to bind OpenGL ES API");
67         return false;
68     }
69 
70     unsigned int ret;
71     EGLint count;
72     EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
73         EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
74 
75     ret = eglChooseConfig(eglDisplay_, configAttribs, &config_, 1, &count);
76     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
77         IMAGE_LOGE("Failed to eglChooseConfig");
78         return false;
79     }
80 
81     static const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
82     eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, contextAttribs);
83     if (eglContext_ == EGL_NO_CONTEXT) {
84         IMAGE_LOGE("Failed to create egl context %{public}x", eglGetError());
85         return false;
86     }
87 
88     if (!CreatePbufferSurface()) {
89         return false;
90     }
91     MakeCurrent(pbufferSurface_);
92 
93     return true;
94 }
95 
CreatePbufferSurface()96 bool RenderContext::CreatePbufferSurface()
97 {
98     if (pbufferSurface_ == EGL_NO_SURFACE) {
99         EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
100         pbufferSurface_ = eglCreatePbufferSurface(eglDisplay_, config_, attribs);
101         if (pbufferSurface_ == EGL_NO_SURFACE) {
102             IMAGE_LOGE(
103                 "RenderContext::CreatePbufferSurface failed, error is %{public}x",
104                 eglGetError());
105             return false;
106         }
107     }
108     return true;
109 }
110 
MakeCurrent(EGLSurface surface) const111 void RenderContext::MakeCurrent(EGLSurface surface) const
112 {
113     EGLSurface currSurface = surface;
114     if (currSurface == EGL_NO_SURFACE) {
115         currSurface = pbufferSurface_;
116     }
117 
118     if (eglMakeCurrent(eglDisplay_, currSurface, currSurface, eglContext_) != EGL_TRUE) {
119         EGLint surfaceId = -1;
120         eglQuerySurface(eglDisplay_, surface, EGL_CONFIG_ID, &surfaceId);
121         IMAGE_LOGE(
122             "RenderContext::MakeCurrent failed for eglSurface %{public}d, error is %{public}x",
123             surfaceId,
124             eglGetError());
125     }
126 }
127 
InitGrContext()128 bool RenderContext::InitGrContext()
129 {
130     sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
131     if (glInterface == nullptr) {
132         IMAGE_LOGE("SetUpGrContext failed to make native interface");
133         return false;
134     }
135 
136     GrContextOptions options;
137     options.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
138     options.fPreferExternalImagesOverES3 = true;
139     options.fDisableDistanceFieldPaths = true;
140     grContext_ = GrDirectContext::MakeGL(std::move(glInterface), options);
141     return grContext_ != nullptr;
142 }
143 
Clear()144 void RenderContext::Clear() noexcept
145 {
146     if (eglDisplay_ == EGL_NO_DISPLAY) {
147         return;
148     }
149 
150     grContext_ = nullptr;
151 
152     if (pbufferSurface_ != EGL_NO_SURFACE) {
153         EGLBoolean ret = eglDestroySurface(eglDisplay_, pbufferSurface_);
154         if (ret != EGL_TRUE) {
155             IMAGE_LOGE("RenderContext::Clear() failed to destroy pbuffer surface, error is %{public}x.", eglGetError());
156         }
157         pbufferSurface_ = EGL_NO_SURFACE;
158     }
159 
160     (void)eglDestroyContext(eglDisplay_, eglContext_);
161     (void)eglTerminate(eglDisplay_);
162     eglContext_ = EGL_NO_CONTEXT;
163     eglDisplay_ = EGL_NO_DISPLAY;
164 }
165 } // namespace Media
166 } // namespace OHOS
167