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