/* * 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 #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_ ); /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is * guaranteed to be accepted by ANativeWindow_setBuffersGeometry(). * As soon as we picked a EGLConfig, we can safely reconfigure the * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */ EGLint format; eglGetConfigAttrib( display_, config_, EGL_NATIVE_VISUAL_ID, &format ); ANativeWindow_setBuffersGeometry( window_, 0, 0, format ); 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