| /* |
| * Copyright 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //-------------------------------------------------------------------------------- |
| // GLContext.cpp |
| //-------------------------------------------------------------------------------- |
| //-------------------------------------------------------------------------------- |
| // includes |
| //-------------------------------------------------------------------------------- |
| #include <unistd.h> |
| #include "GLContext.h" |
| #include "gl3stub.h" |
| |
| namespace ndk_helper |
| { |
| |
| //-------------------------------------------------------------------------------- |
| // eGLContext |
| //-------------------------------------------------------------------------------- |
| |
| //-------------------------------------------------------------------------------- |
| // Ctor |
| //-------------------------------------------------------------------------------- |
| GLContext::GLContext() : |
| display_( EGL_NO_DISPLAY ), |
| surface_( EGL_NO_SURFACE ), |
| context_( EGL_NO_CONTEXT ), |
| screen_width_( 0 ), |
| screen_height_( 0 ), |
| es3_supported_( false ), |
| egl_context_initialized_( false ), |
| gles_initialized_( false ) |
| { |
| } |
| |
| void GLContext::InitGLES() |
| { |
| if( gles_initialized_ ) |
| return; |
| // |
| //Initialize OpenGL ES 3 if available |
| // |
| const char* versionStr = (const char*) glGetString( GL_VERSION ); |
| if( strstr( versionStr, "OpenGL ES 3." ) && gl3stubInit() ) |
| { |
| es3_supported_ = true; |
| gl_version_ = 3.0f; |
| } |
| else |
| { |
| gl_version_ = 2.0f; |
| } |
| |
| gles_initialized_ = true; |
| } |
| |
| //-------------------------------------------------------------------------------- |
| // Dtor |
| //-------------------------------------------------------------------------------- |
| GLContext::~GLContext() |
| { |
| Terminate(); |
| } |
| |
| bool GLContext::Init( ANativeWindow* window ) |
| { |
| if( egl_context_initialized_ ) |
| return true; |
| |
| // |
| //Initialize EGL |
| // |
| window_ = window; |
| InitEGLSurface(); |
| InitEGLContext(); |
| InitGLES(); |
| |
| egl_context_initialized_ = true; |
| |
| return true; |
| } |
| |
| bool GLContext::InitEGLSurface() |
| { |
| display_ = eglGetDisplay( EGL_DEFAULT_DISPLAY ); |
| eglInitialize( display_, 0, 0 ); |
| |
| /* |
| * Here specify the attributes of the desired configuration. |
| * Below, we select an EGLConfig with at least 8 bits per color |
| * component compatible with on-screen windows |
| */ |
| const EGLint attribs[] = { EGL_RENDERABLE_TYPE, |
| EGL_OPENGL_ES2_BIT, //Request opengl ES2.0 |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, |
| EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_NONE }; |
| color_size_ = 8; |
| depth_size_ = 24; |
| |
| EGLint num_configs; |
| eglChooseConfig( display_, attribs, &config_, 1, &num_configs ); |
| |
| if( !num_configs ) |
| { |
| //Fall back to 16bit depth buffer |
| const EGLint attribs[] = { EGL_RENDERABLE_TYPE, |
| EGL_OPENGL_ES2_BIT, //Request opengl ES2.0 |
| EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, |
| EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 16, EGL_NONE }; |
| eglChooseConfig( display_, attribs, &config_, 1, &num_configs ); |
| depth_size_ = 16; |
| } |
| |
| if( !num_configs ) |
| { |
| LOGW( "Unable to retrieve EGL config" ); |
| return false; |
| } |
| |
| surface_ = eglCreateWindowSurface( display_, config_, window_, NULL ); |
| eglQuerySurface( display_, surface_, EGL_WIDTH, &screen_width_ ); |
| eglQuerySurface( display_, surface_, EGL_HEIGHT, &screen_height_ ); |
| |
| return true; |
| } |
| |
| bool GLContext::InitEGLContext() |
| { |
| const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, //Request opengl ES2.0 |
| EGL_NONE }; |
| context_ = eglCreateContext( display_, config_, NULL, context_attribs ); |
| |
| if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_FALSE ) |
| { |
| LOGW( "Unable to eglMakeCurrent" ); |
| return false; |
| } |
| |
| context_valid_ = true; |
| return true; |
| } |
| |
| EGLint GLContext::Swap() |
| { |
| bool b = eglSwapBuffers( display_, surface_ ); |
| if( !b ) |
| { |
| EGLint err = eglGetError(); |
| if( err == EGL_BAD_SURFACE ) |
| { |
| //Recreate surface |
| InitEGLSurface(); |
| return EGL_SUCCESS; //Still consider glContext is valid |
| } |
| else if( err == EGL_CONTEXT_LOST || err == EGL_BAD_CONTEXT ) |
| { |
| //Context has been lost!! |
| context_valid_ = false; |
| Terminate(); |
| InitEGLContext(); |
| } |
| return err; |
| } |
| return EGL_SUCCESS; |
| } |
| |
| void GLContext::Terminate() |
| { |
| if( display_ != EGL_NO_DISPLAY ) |
| { |
| eglMakeCurrent( display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); |
| if( context_ != EGL_NO_CONTEXT ) |
| { |
| eglDestroyContext( display_, context_ ); |
| } |
| |
| if( surface_ != EGL_NO_SURFACE ) |
| { |
| eglDestroySurface( display_, surface_ ); |
| } |
| eglTerminate( display_ ); |
| } |
| |
| display_ = EGL_NO_DISPLAY; |
| context_ = EGL_NO_CONTEXT; |
| surface_ = EGL_NO_SURFACE; |
| context_valid_ = false; |
| |
| } |
| |
| EGLint GLContext::Resume( ANativeWindow* window ) |
| { |
| if( egl_context_initialized_ == false ) |
| { |
| Init( window ); |
| return EGL_SUCCESS; |
| } |
| |
| int32_t original_widhth = screen_width_; |
| int32_t original_height = screen_height_; |
| |
| //Create surface |
| window_ = window; |
| surface_ = eglCreateWindowSurface( display_, config_, window_, NULL ); |
| eglQuerySurface( display_, surface_, EGL_WIDTH, &screen_width_ ); |
| eglQuerySurface( display_, surface_, EGL_HEIGHT, &screen_height_ ); |
| |
| if( screen_width_ != original_widhth || screen_height_ != original_height ) |
| { |
| //Screen resized |
| LOGI( "Screen resized" ); |
| } |
| |
| if( eglMakeCurrent( display_, surface_, surface_, context_ ) == EGL_TRUE ) |
| return EGL_SUCCESS; |
| |
| EGLint err = eglGetError(); |
| LOGW( "Unable to eglMakeCurrent %d", err ); |
| |
| if( err == EGL_CONTEXT_LOST ) |
| { |
| //Recreate context |
| LOGI( "Re-creating egl context" ); |
| InitEGLContext(); |
| } |
| else |
| { |
| //Recreate surface |
| Terminate(); |
| InitEGLSurface(); |
| InitEGLContext(); |
| } |
| |
| return err; |
| |
| } |
| |
| void GLContext::Suspend() |
| { |
| if( surface_ != EGL_NO_SURFACE ) |
| { |
| eglDestroySurface( display_, surface_ ); |
| surface_ = EGL_NO_SURFACE; |
| } |
| } |
| |
| bool GLContext::Invalidate() |
| { |
| Terminate(); |
| |
| egl_context_initialized_ = false; |
| return true; |
| } |
| |
| bool GLContext::CheckExtension( const char* extension ) |
| { |
| if( extension == NULL ) |
| return false; |
| |
| std::string extensions = std::string( (char*) glGetString( GL_EXTENSIONS ) ); |
| std::string str = std::string( extension ); |
| str.append( " " ); |
| |
| size_t pos = 0; |
| if( extensions.find( extension, pos ) != std::string::npos ) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| } //namespace ndkHelper |