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