Home | History | Annotate | Download | only in ndk_helper
      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