Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2011 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 // #define LOG_NDEBUG 0
     17 
     18 #include "base/logging.h"
     19 #include "base/utilities.h"
     20 #include "core/gl_env.h"
     21 #include "core/shader_program.h"
     22 #include "core/vertex_frame.h"
     23 #include "system/window.h"
     24 
     25 #include <map>
     26 #include <string>
     27 #include <EGL/eglext.h>
     28 
     29 #include <gui/GLConsumer.h>
     30 
     31 namespace android {
     32 namespace filterfw {
     33 
     34 GLEnv::GLEnv()
     35   : display_(EGL_NO_DISPLAY),
     36     context_id_(0),
     37     surface_id_(0),
     38     max_surface_id_(0),
     39     created_context_(false),
     40     created_surface_(false),
     41     initialized_(false) {
     42 }
     43 
     44 GLEnv::~GLEnv() {
     45   // Destroy surfaces
     46   for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
     47        it != surfaces_.end();
     48        ++it) {
     49     if (it->first != 0 || created_surface_) {
     50       eglDestroySurface(display(), it->second.first);
     51       if (it->second.second) {
     52         it->second.second->Destroy();
     53         delete it->second.second;
     54       }
     55     }
     56   }
     57 
     58   // Destroy contexts
     59   for (std::map<int, EGLContext>::iterator it = contexts_.begin();
     60        it != contexts_.end();
     61        ++it) {
     62     if (it->first != 0 || created_context_)
     63       eglDestroyContext(display(), it->second);
     64   }
     65 
     66   // Destroy attached shaders and frames
     67   STLDeleteValues(&attached_shaders_);
     68   STLDeleteValues(&attached_vframes_);
     69 
     70   // Destroy display
     71   if (initialized_)
     72     eglTerminate(display());
     73 
     74   // Log error if this did not work
     75   if (CheckEGLError("TearDown!"))
     76     ALOGE("GLEnv: Error tearing down GL Environment!");
     77 }
     78 
     79 bool GLEnv::IsInitialized() const {
     80   return (contexts_.size() > 0 &&
     81           surfaces_.size() > 0 &&
     82           display_ != EGL_NO_DISPLAY);
     83 }
     84 
     85 bool GLEnv::Deactivate() {
     86   eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     87   return !CheckEGLError("eglMakeCurrent");
     88 }
     89 
     90 bool GLEnv::Activate() {
     91   ALOGV("Activate()");
     92   if (display()   != eglGetCurrentDisplay() ||
     93       context()   != eglGetCurrentContext() ||
     94       surface()   != eglGetCurrentSurface(EGL_DRAW)) {
     95     // Make sure we are initialized
     96     if (context() == EGL_NO_CONTEXT || surface() == EGL_NO_SURFACE)
     97       return false;
     98 
     99     // Make our context current
    100     ALOGV("eglMakeCurrent");
    101     eglMakeCurrent(display(), surface(), surface(), context());
    102 
    103     return !CheckEGLMakeCurrentError();
    104   }
    105   return true;
    106 }
    107 
    108 bool GLEnv::SwapBuffers() {
    109   const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE;
    110   return !CheckEGLError("eglSwapBuffers") && result;
    111 }
    112 
    113 bool GLEnv::InitWithCurrentContext() {
    114   if (IsInitialized())
    115     return true;
    116 
    117   display_     = eglGetCurrentDisplay();
    118   contexts_[0] = eglGetCurrentContext();
    119   surfaces_[0] = SurfaceWindowPair(eglGetCurrentSurface(EGL_DRAW), NULL);
    120 
    121   return (context() != EGL_NO_CONTEXT) &&
    122          (display() != EGL_NO_DISPLAY) &&
    123          (surface() != EGL_NO_SURFACE);
    124 }
    125 
    126 bool GLEnv::InitWithNewContext() {
    127   if (IsInitialized()) {
    128     ALOGE("GLEnv: Attempting to reinitialize environment!");
    129     return false;
    130   }
    131 
    132   display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    133   if (CheckEGLError("eglGetDisplay")) return false;
    134 
    135   EGLint majorVersion;
    136   EGLint minorVersion;
    137   eglInitialize(display(), &majorVersion, &minorVersion);
    138   if (CheckEGLError("eglInitialize")) return false;
    139   initialized_ = true;
    140 
    141   // Configure context/surface
    142   EGLConfig config;
    143   EGLint numConfigs = -1;
    144 
    145   // TODO(renn): Do we need the window bit here?
    146   // TODO: Currently choosing the config that includes all
    147   // This is not needed if the encoding is not being used
    148   EGLint configAttribs[] = {
    149     EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    150     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    151     EGL_RED_SIZE, 8,
    152     EGL_GREEN_SIZE, 8,
    153     EGL_BLUE_SIZE, 8,
    154     EGL_RECORDABLE_ANDROID, EGL_TRUE,
    155     EGL_NONE
    156   };
    157 
    158   eglChooseConfig(display(), configAttribs, &config, 1, &numConfigs);
    159   if (numConfigs < 1) {
    160     ALOGE("GLEnv::Init: No suitable EGL configuration found!");
    161     return false;
    162   }
    163 
    164   // Create dummy surface using a GLConsumer
    165   sp<IGraphicBufferProducer> producer;
    166   sp<IGraphicBufferConsumer> consumer;
    167   BufferQueue::createBufferQueue(&producer, &consumer);
    168   surfaceTexture_ = new GLConsumer(consumer, 0, GLConsumer::TEXTURE_EXTERNAL,
    169           true, false);
    170   window_ = new Surface(producer);
    171 
    172   surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL);
    173   if (CheckEGLError("eglCreateWindowSurface")) return false;
    174 
    175   // Create context
    176   EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    177   contexts_[0] = eglCreateContext(display(),
    178                                   config,
    179                                   EGL_NO_CONTEXT,
    180                                   context_attribs);
    181   if (CheckEGLError("eglCreateContext")) return false;
    182 
    183   created_context_ = created_surface_ = true;
    184 
    185   return true;
    186 }
    187 
    188 bool GLEnv::IsActive() const {
    189   ALOGV("IsActive()");
    190   return context() == eglGetCurrentContext()
    191     &&   display() == eglGetCurrentDisplay()
    192     &&   surface() == eglGetCurrentSurface(EGL_DRAW);
    193 }
    194 
    195 bool GLEnv::IsContextActive() const {
    196   return context() == eglGetCurrentContext();
    197 }
    198 
    199 bool GLEnv::IsAnyContextActive() {
    200   return eglGetCurrentContext() != EGL_NO_CONTEXT;
    201 }
    202 
    203 int GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) {
    204   const int id = ++max_surface_id_;
    205   surfaces_[id] = SurfaceWindowPair(surface, window_handle);
    206   return id;
    207 }
    208 
    209 int GLEnv::AddSurface(const EGLSurface& surface) {
    210   return AddWindowSurface(surface, NULL);
    211 }
    212 
    213 bool GLEnv::SwitchToSurfaceId(int surface_id) {
    214   ALOGV("SwitchToSurfaceId");
    215   if (surface_id_ != surface_id) {
    216     const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id);
    217     if (surface) {
    218       bool wasActive = IsActive();
    219       surface_id_ = surface_id;
    220       return wasActive ? Activate() : true;
    221     }
    222     return false;
    223   }
    224   return true;
    225 }
    226 
    227 bool GLEnv::ReleaseSurfaceId(int surface_id) {
    228   if (surface_id > 0) {
    229     const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id);
    230     if (surface_window_pair) {
    231       if (surface_id_ == surface_id)
    232         SwitchToSurfaceId(0);
    233       eglDestroySurface(display(), surface_window_pair->first);
    234       if (surface_window_pair->second) {
    235         surface_window_pair->second->Destroy();
    236         delete surface_window_pair->second;
    237       }
    238       surfaces_.erase(surface_id);
    239       return true;
    240     }
    241   }
    242   return false;
    243 }
    244 
    245 bool GLEnv::SetSurfaceTimestamp(int64_t timestamp) {
    246   if (surface_id_ > 0) {
    247     const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_,
    248             surface_id_);
    249     if (surface_window_pair) {
    250       ANativeWindow *window = static_cast<ANativeWindow*>(
    251               surface_window_pair->second->InternalHandle());
    252       native_window_set_buffers_timestamp(window, timestamp);
    253       return true;
    254     }
    255   }
    256   return false;
    257 }
    258 
    259 int GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) {
    260   for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin();
    261        it != surfaces_.end();
    262        ++it) {
    263     const WindowHandle* my_handle = it->second.second;
    264     if (my_handle && my_handle->Equals(window_handle)) {
    265       return it->first;
    266     }
    267   }
    268   return -1;
    269 }
    270 
    271 
    272 int GLEnv::AddContext(const EGLContext& context) {
    273   const int id = contexts_.size();
    274   contexts_[id] = context;
    275   return id;
    276 }
    277 
    278 bool GLEnv::SwitchToContextId(int context_id) {
    279   const EGLContext* context = FindOrNull(contexts_, context_id);
    280   if (context) {
    281     if (context_id_ != context_id) {
    282       context_id_ = context_id;
    283       return Activate();
    284     }
    285     return true;
    286   }
    287   return false;
    288 }
    289 
    290 void GLEnv::ReleaseContextId(int context_id) {
    291   if (context_id > 0) {
    292     const EGLContext* context = FindOrNull(contexts_, context_id);
    293     if (context) {
    294       contexts_.erase(context_id);
    295       if (context_id_ == context_id && IsActive())
    296         SwitchToContextId(0);
    297       eglDestroyContext(display(), *context);
    298     }
    299   }
    300 }
    301 
    302 bool GLEnv::CheckGLError(const std::string& op) {
    303   bool err = false;
    304   for (GLint error = glGetError(); error; error = glGetError()) {
    305     ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n",
    306          op.c_str(),
    307          error);
    308     err = true;
    309   }
    310   return err;
    311 }
    312 
    313 bool GLEnv::CheckEGLError(const std::string& op) {
    314   bool err = false;
    315   for (EGLint error = eglGetError();
    316        error != EGL_SUCCESS;
    317        error = eglGetError()) {
    318     ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n",
    319          op.c_str(),
    320          error);
    321     err = true;
    322   }
    323   return err;
    324 }
    325 
    326 bool GLEnv::CheckEGLMakeCurrentError() {
    327   bool err = false;
    328   for (EGLint error = eglGetError();
    329        error != EGL_SUCCESS;
    330        error = eglGetError()) {
    331     switch (error) {
    332       case EGL_BAD_DISPLAY:
    333         ALOGE("EGL Error: Attempting to activate context with bad display!");
    334         break;
    335       case EGL_BAD_SURFACE:
    336         ALOGE("EGL Error: Attempting to activate context with bad surface!");
    337         break;
    338       case EGL_BAD_ACCESS:
    339         ALOGE("EGL Error: Attempting to activate context, which is "
    340              "already active in another thread!");
    341         break;
    342       default:
    343         ALOGE("EGL Error: Making EGL rendering context current caused "
    344              "error: 0x%x\n", error);
    345     }
    346     err = true;
    347   }
    348   return err;
    349 }
    350 
    351 GLuint GLEnv::GetCurrentProgram() {
    352   GLint result;
    353   glGetIntegerv(GL_CURRENT_PROGRAM, &result);
    354   ALOG_ASSERT(result >= 0);
    355   return static_cast<GLuint>(result);
    356 }
    357 
    358 EGLDisplay GLEnv::GetCurrentDisplay() {
    359   return eglGetCurrentDisplay();
    360 }
    361 
    362 int GLEnv::NumberOfComponents(GLenum type) {
    363   switch (type) {
    364     case GL_BOOL:
    365     case GL_FLOAT:
    366     case GL_INT:
    367       return 1;
    368     case GL_BOOL_VEC2:
    369     case GL_FLOAT_VEC2:
    370     case GL_INT_VEC2:
    371       return 2;
    372     case GL_INT_VEC3:
    373     case GL_FLOAT_VEC3:
    374     case GL_BOOL_VEC3:
    375       return 3;
    376     case GL_BOOL_VEC4:
    377     case GL_FLOAT_VEC4:
    378     case GL_INT_VEC4:
    379     case GL_FLOAT_MAT2:
    380       return 4;
    381     case GL_FLOAT_MAT3:
    382       return 9;
    383     case GL_FLOAT_MAT4:
    384       return 16;
    385     default:
    386       return 0;
    387   }
    388 }
    389 
    390 void GLEnv::AttachShader(int key, ShaderProgram* shader) {
    391   ShaderProgram* existingShader = ShaderWithKey(key);
    392   if (existingShader)
    393     delete existingShader;
    394   attached_shaders_[key] = shader;
    395 }
    396 
    397 void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) {
    398   VertexFrame* existingFrame = VertexFrameWithKey(key);
    399   if (existingFrame)
    400     delete existingFrame;
    401   attached_vframes_[key] = frame;
    402 }
    403 
    404 ShaderProgram* GLEnv::ShaderWithKey(int key) {
    405   return FindPtrOrNull(attached_shaders_, key);
    406 }
    407 
    408 VertexFrame* GLEnv::VertexFrameWithKey(int key) {
    409   return FindPtrOrNull(attached_vframes_, key);
    410 }
    411 
    412 } // namespace filterfw
    413 } // namespace android
    414