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 //-------------------------------------------------------------------------------- 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 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 //-------------------------------------------------------------------------------- 73 GLContext::~GLContext() 74 { 75 Terminate(); 76 } 77 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 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 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 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 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 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 259 void GLContext::Suspend() 260 { 261 if( surface_ != EGL_NO_SURFACE ) 262 { 263 eglDestroySurface( display_, surface_ ); 264 surface_ = EGL_NO_SURFACE; 265 } 266 } 267 268 bool GLContext::Invalidate() 269 { 270 Terminate(); 271 272 egl_context_initialized_ = false; 273 return true; 274 } 275 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