1 /*
2 * Copyright 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //--------------------------------------------------------------------------------
18 // GLContext.cpp
19 //--------------------------------------------------------------------------------
20 //--------------------------------------------------------------------------------
21 // includes
22 //--------------------------------------------------------------------------------
23 #include <unistd.h>
24 #include "GLContext.h"
25 #include "gl3stub.h"
26
27 namespace ndk_helper
28 {
29
30 //--------------------------------------------------------------------------------
31 // eGLContext
32 //--------------------------------------------------------------------------------
33
34 //--------------------------------------------------------------------------------
35 // Ctor
36 //--------------------------------------------------------------------------------
GLContext()37 GLContext::GLContext() :
38 display_( EGL_NO_DISPLAY ),
39 surface_( EGL_NO_SURFACE ),
40 context_( EGL_NO_CONTEXT ),
41 screen_width_( 0 ),
42 screen_height_( 0 ),
43 es3_supported_( false ),
44 egl_context_initialized_( false ),
45 gles_initialized_( false )
46 {
47 }
48
InitGLES()49 void GLContext::InitGLES()
50 {
51 if( gles_initialized_ )
52 return;
53 //
54 //Initialize OpenGL ES 3 if available
55 //
56 const char* versionStr = (const char*) glGetString( GL_VERSION );
57 if( strstr( versionStr, "OpenGL ES 3." ) && gl3stubInit() )
58 {
59 es3_supported_ = true;
60 gl_version_ = 3.0f;
61 }
62 else
63 {
64 gl_version_ = 2.0f;
65 }
66
67 gles_initialized_ = true;
68 }
69
70 //--------------------------------------------------------------------------------
71 // Dtor
72 //--------------------------------------------------------------------------------
~GLContext()73 GLContext::~GLContext()
74 {
75 Terminate();
76 }
77
Init(ANativeWindow * window)78 bool GLContext::Init( ANativeWindow* window )
79 {
80 if( egl_context_initialized_ )
81 return true;
82
83 //
84 //Initialize EGL
85 //
86 window_ = window;
87 InitEGLSurface();
88 InitEGLContext();
89 InitGLES();
90
91 egl_context_initialized_ = true;
92
93 return true;
94 }
95
InitEGLSurface()96 bool GLContext::InitEGLSurface()
97 {
98 display_ = eglGetDisplay( EGL_DEFAULT_DISPLAY );
99 eglInitialize( display_, 0, 0 );
100
101 /*
102 * Here specify the attributes of the desired configuration.
103 * Below, we select an EGLConfig with at least 8 bits per color
104 * component compatible with on-screen windows
105 */
106 const EGLint attribs[] = { EGL_RENDERABLE_TYPE,
107 EGL_OPENGL_ES2_BIT, //Request opengl ES2.0
108 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8,
109 EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_NONE };
110 color_size_ = 8;
111 depth_size_ = 24;
112
113 EGLint num_configs;
114 eglChooseConfig( display_, attribs, &config_, 1, &num_configs );
115
116 if( !num_configs )
117 {
118 //Fall back to 16bit depth buffer
119 const EGLint attribs[] = { EGL_RENDERABLE_TYPE,
120 EGL_OPENGL_ES2_BIT, //Request opengl ES2.0
121 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8,
122 EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_NONE };
123 eglChooseConfig( display_, attribs, &config_, 1, &num_configs );
124 depth_size_ = 16;
125 }
126
127 if( !num_configs )
128 {
129 LOGW( "Unable to retrieve EGL config" );
130 return false;
131 }
132
133 surface_ = eglCreateWindowSurface( display_, config_, window_, NULL );
134 eglQuerySurface( display_, surface_, EGL_WIDTH, &screen_width_ );
135 eglQuerySurface( display_, surface_, EGL_HEIGHT, &screen_height_ );
136
137 /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
138 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
139 * As soon as we picked a EGLConfig, we can safely reconfigure the
140 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
141 EGLint format;
142 eglGetConfigAttrib( display_, config_, EGL_NATIVE_VISUAL_ID, &format );
143 ANativeWindow_setBuffersGeometry( window_, 0, 0, format );
144
145 return true;
146 }
147
InitEGLContext()148 bool GLContext::InitEGLContext()
149 {
150 const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, //Request opengl ES2.0
151 EGL_NONE };
152 context_ = eglCreateContext( display_, config_, NULL, context_attribs );
153
154 if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_FALSE )
155 {
156 LOGW( "Unable to eglMakeCurrent" );
157 return false;
158 }
159
160 context_valid_ = true;
161 return true;
162 }
163
Swap()164 EGLint GLContext::Swap()
165 {
166 bool b = eglSwapBuffers( display_, surface_ );
167 if( !b )
168 {
169 EGLint err = eglGetError();
170 if( err == EGL_BAD_SURFACE )
171 {
172 //Recreate surface
173 InitEGLSurface();
174 return EGL_SUCCESS; //Still consider glContext is valid
175 }
176 else if( err == EGL_CONTEXT_LOST || err == EGL_BAD_CONTEXT )
177 {
178 //Context has been lost!!
179 context_valid_ = false;
180 Terminate();
181 InitEGLContext();
182 }
183 return err;
184 }
185 return EGL_SUCCESS;
186 }
187
Terminate()188 void GLContext::Terminate()
189 {
190 if( display_ != EGL_NO_DISPLAY )
191 {
192 eglMakeCurrent( display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
193 if( context_ != EGL_NO_CONTEXT )
194 {
195 eglDestroyContext( display_, context_ );
196 }
197
198 if( surface_ != EGL_NO_SURFACE )
199 {
200 eglDestroySurface( display_, surface_ );
201 }
202 eglTerminate( display_ );
203 }
204
205 display_ = EGL_NO_DISPLAY;
206 context_ = EGL_NO_CONTEXT;
207 surface_ = EGL_NO_SURFACE;
208 context_valid_ = false;
209
210 }
211
Resume(ANativeWindow * window)212 EGLint GLContext::Resume( ANativeWindow* window )
213 {
214 if( egl_context_initialized_ == false )
215 {
216 Init( window );
217 return EGL_SUCCESS;
218 }
219
220 int32_t original_widhth = screen_width_;
221 int32_t original_height = screen_height_;
222
223 //Create surface
224 window_ = window;
225 surface_ = eglCreateWindowSurface( display_, config_, window_, NULL );
226 eglQuerySurface( display_, surface_, EGL_WIDTH, &screen_width_ );
227 eglQuerySurface( display_, surface_, EGL_HEIGHT, &screen_height_ );
228
229 if( screen_width_ != original_widhth || screen_height_ != original_height )
230 {
231 //Screen resized
232 LOGI( "Screen resized" );
233 }
234
235 if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_TRUE )
236 return EGL_SUCCESS;
237
238 EGLint err = eglGetError();
239 LOGW( "Unable to eglMakeCurrent %d", err );
240
241 if( err == EGL_CONTEXT_LOST )
242 {
243 //Recreate context
244 LOGI( "Re-creating egl context" );
245 InitEGLContext();
246 }
247 else
248 {
249 //Recreate surface
250 Terminate();
251 InitEGLSurface();
252 InitEGLContext();
253 }
254
255 return err;
256
257 }
258
Suspend()259 void GLContext::Suspend()
260 {
261 if( surface_ != EGL_NO_SURFACE )
262 {
263 eglDestroySurface( display_, surface_ );
264 surface_ = EGL_NO_SURFACE;
265 }
266 }
267
Invalidate()268 bool GLContext::Invalidate()
269 {
270 Terminate();
271
272 egl_context_initialized_ = false;
273 return true;
274 }
275
CheckExtension(const char * extension)276 bool GLContext::CheckExtension( const char* extension )
277 {
278 if( extension == NULL )
279 return false;
280
281 std::string extensions = std::string( (char*) glGetString( GL_EXTENSIONS ) );
282 std::string str = std::string( extension );
283 str.append( " " );
284
285 size_t pos = 0;
286 if( extensions.find( extension, pos ) != std::string::npos )
287 {
288 return true;
289 }
290
291 return false;
292 }
293
294 } //namespace ndkHelper
295