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 "offscreen_context_helper.h"
17 #include <EGL/egl.h>
18 #include <EGL/eglext.h>
19 #include <GLES/gl.h>
20 #include <window.h>
21 
22 #include <3d_widget_adapter_log.h>
23 
24 
25 namespace OHOS::Render3D {
AutoRestore()26 AutoRestore::AutoRestore()
27 {
28     c_ = eglGetCurrentContext();
29     rs_ = eglGetCurrentSurface(EGL_READ);
30     ws_ = eglGetCurrentSurface(EGL_DRAW);
31     d_ = eglGetCurrentDisplay();
32     if (d_ == EGL_NO_DISPLAY) {
33         d_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
34     }
35     if (!eglMakeCurrent(d_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
36         WIDGET_LOGE("AutoRestore make current error %d", eglGetError());
37     }
38 }
39 
~AutoRestore()40 AutoRestore::~AutoRestore()
41 {
42     if (!eglMakeCurrent(d_, ws_, rs_, c_)) {
43         WIDGET_LOGE("~AutoRestore make current error %d", eglGetError());
44     }
45 }
46 
~OffScreenContextHelper()47 OffScreenContextHelper::~OffScreenContextHelper()
48 {
49     DestroyOffScreenContext();
50 }
51 
CreateOffScreenContext(EGLContext eglContext)52 EGLContext OffScreenContextHelper::CreateOffScreenContext(EGLContext eglContext)
53 {
54     if (localThreadContext_ != EGL_NO_CONTEXT) {
55         return localThreadContext_;
56     }
57 
58     eglDisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
59     if (eglContext == EGL_NO_CONTEXT) {
60         EGLint major = 0;
61         EGLint minor = 0;
62         if (!eglInitialize(eglDisplay_, &major, &minor)) {
63             WIDGET_LOGW("Initialize egl fail");
64         }
65         if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
66             WIDGET_LOGW("faile to bind gles api");
67         }
68     }
69 
70     EGLint contextAttrs[] = {
71         EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 2,
72         EGL_NONE, EGL_NONE,
73     };
74     EGLint configAttribs[] = {
75         EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_RED_SIZE, 8,
76         EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0,
77         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR, EGL_CONFORMANT, EGL_OPENGL_ES3_BIT_KHR, EGL_NONE, EGL_NONE,
78     };
79     EGLint count = -1;
80     EGLConfig config;
81 
82     if (!eglChooseConfig(eglDisplay_, configAttribs, &config, 1, &count)) {
83         WIDGET_LOGE("eglChooseConfig error %d", eglGetError());
84         return EGL_NO_CONTEXT;
85     }
86 
87     localThreadContext_ = eglCreateContext(eglDisplay_, config, eglContext, contextAttrs);
88     auto error = eglGetError();
89     if (error != EGL_SUCCESS) {
90         WIDGET_LOGE("create context fail %d", error);
91         return EGL_NO_CONTEXT;
92     }
93 
94     EGLint pbufferAttribs[] = {
95         EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE,
96     };
97     pBufferSurface_ = eglCreatePbufferSurface(eglDisplay_, config, pbufferAttribs);
98     return localThreadContext_;
99 }
100 
GetOffScreenContext()101 EGLContext OffScreenContextHelper::GetOffScreenContext()
102 {
103     return localThreadContext_;
104 }
105 
BindOffScreenContext()106 void OffScreenContextHelper::BindOffScreenContext()
107 {
108     if (!eglMakeCurrent(eglDisplay_, pBufferSurface_, pBufferSurface_, localThreadContext_)) {
109         WIDGET_LOGE("%s, eglMakecurrent error %d", __func__, eglGetError());
110     }
111 }
112 
DestroyOffScreenContext()113 void OffScreenContextHelper::DestroyOffScreenContext()
114 {
115     WIDGET_LOGI("DestroyOffScreenContext");
116     if (pBufferSurface_ != EGL_NO_SURFACE) {
117         eglDestroySurface(eglDisplay_, pBufferSurface_);
118         pBufferSurface_ = EGL_NO_SURFACE;
119     }
120 
121     if (localThreadContext_ != EGL_NO_CONTEXT) {
122         eglDestroyContext(eglDisplay_, localThreadContext_);
123         localThreadContext_ = EGL_NO_CONTEXT;
124     }
125 }
126 } // namespace OHOS::Render3D
127