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 27namespace ndk_helper 28{ 29 30//-------------------------------------------------------------------------------- 31// eGLContext 32//-------------------------------------------------------------------------------- 33 34//-------------------------------------------------------------------------------- 35// Ctor 36//-------------------------------------------------------------------------------- 37GLContext::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 49void 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//-------------------------------------------------------------------------------- 73GLContext::~GLContext() 74{ 75 Terminate(); 76} 77 78bool 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 96bool 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 return true; 138} 139 140bool GLContext::InitEGLContext() 141{ 142 const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, //Request opengl ES2.0 143 EGL_NONE }; 144 context_ = eglCreateContext( display_, config_, NULL, context_attribs ); 145 146 if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_FALSE ) 147 { 148 LOGW( "Unable to eglMakeCurrent" ); 149 return false; 150 } 151 152 context_valid_ = true; 153 return true; 154} 155 156EGLint GLContext::Swap() 157{ 158 bool b = eglSwapBuffers( display_, surface_ ); 159 if( !b ) 160 { 161 EGLint err = eglGetError(); 162 if( err == EGL_BAD_SURFACE ) 163 { 164 //Recreate surface 165 InitEGLSurface(); 166 return EGL_SUCCESS; //Still consider glContext is valid 167 } 168 else if( err == EGL_CONTEXT_LOST || err == EGL_BAD_CONTEXT ) 169 { 170 //Context has been lost!! 171 context_valid_ = false; 172 Terminate(); 173 InitEGLContext(); 174 } 175 return err; 176 } 177 return EGL_SUCCESS; 178} 179 180void GLContext::Terminate() 181{ 182 if( display_ != EGL_NO_DISPLAY ) 183 { 184 eglMakeCurrent( display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); 185 if( context_ != EGL_NO_CONTEXT ) 186 { 187 eglDestroyContext( display_, context_ ); 188 } 189 190 if( surface_ != EGL_NO_SURFACE ) 191 { 192 eglDestroySurface( display_, surface_ ); 193 } 194 eglTerminate( display_ ); 195 } 196 197 display_ = EGL_NO_DISPLAY; 198 context_ = EGL_NO_CONTEXT; 199 surface_ = EGL_NO_SURFACE; 200 context_valid_ = false; 201 202} 203 204EGLint GLContext::Resume( ANativeWindow* window ) 205{ 206 if( egl_context_initialized_ == false ) 207 { 208 Init( window ); 209 return EGL_SUCCESS; 210 } 211 212 int32_t original_widhth = screen_width_; 213 int32_t original_height = screen_height_; 214 215 //Create surface 216 window_ = window; 217 surface_ = eglCreateWindowSurface( display_, config_, window_, NULL ); 218 eglQuerySurface( display_, surface_, EGL_WIDTH, &screen_width_ ); 219 eglQuerySurface( display_, surface_, EGL_HEIGHT, &screen_height_ ); 220 221 if( screen_width_ != original_widhth || screen_height_ != original_height ) 222 { 223 //Screen resized 224 LOGI( "Screen resized" ); 225 } 226 227 if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_TRUE ) 228 return EGL_SUCCESS; 229 230 EGLint err = eglGetError(); 231 LOGW( "Unable to eglMakeCurrent %d", err ); 232 233 if( err == EGL_CONTEXT_LOST ) 234 { 235 //Recreate context 236 LOGI( "Re-creating egl context" ); 237 InitEGLContext(); 238 } 239 else 240 { 241 //Recreate surface 242 Terminate(); 243 InitEGLSurface(); 244 InitEGLContext(); 245 } 246 247 return err; 248 249} 250 251void GLContext::Suspend() 252{ 253 if( surface_ != EGL_NO_SURFACE ) 254 { 255 eglDestroySurface( display_, surface_ ); 256 surface_ = EGL_NO_SURFACE; 257 } 258} 259 260bool GLContext::Invalidate() 261{ 262 Terminate(); 263 264 egl_context_initialized_ = false; 265 return true; 266} 267 268bool GLContext::CheckExtension( const char* extension ) 269{ 270 if( extension == NULL ) 271 return false; 272 273 std::string extensions = std::string( (char*) glGetString( GL_EXTENSIONS ) ); 274 std::string str = std::string( extension ); 275 str.append( " " ); 276 277 size_t pos = 0; 278 if( extensions.find( extension, pos ) != std::string::npos ) 279 { 280 return true; 281 } 282 283 return false; 284} 285 286} //namespace ndkHelper 287