diff options
Diffstat (limited to 'media/mca/filterfw/native/core/gl_env.cpp')
-rw-r--r-- | media/mca/filterfw/native/core/gl_env.cpp | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp new file mode 100644 index 0000000..738b8e0 --- /dev/null +++ b/media/mca/filterfw/native/core/gl_env.cpp @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2011 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. + */ +// #define LOG_NDEBUG 0 + +#include "base/logging.h" +#include "base/utilities.h" +#include "core/gl_env.h" +#include "core/shader_program.h" +#include "core/vertex_frame.h" +#include "system/window.h" + +#include <map> +#include <string> +#include <EGL/eglext.h> + +namespace android { +namespace filterfw { + +GLEnv::GLEnv() + : display_(EGL_NO_DISPLAY), + context_id_(0), + surface_id_(0), + max_surface_id_(0), + created_context_(false), + created_surface_(false), + initialized_(false) { +} + +GLEnv::~GLEnv() { + // Destroy surfaces + for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin(); + it != surfaces_.end(); + ++it) { + if (it->first != 0 || created_surface_) { + eglDestroySurface(display(), it->second.first); + if (it->second.second) { + it->second.second->Destroy(); + delete it->second.second; + } + } + } + + // Destroy contexts + for (std::map<int, EGLContext>::iterator it = contexts_.begin(); + it != contexts_.end(); + ++it) { + if (it->first != 0 || created_context_) + eglDestroyContext(display(), it->second); + } + + // Destroy attached shaders and frames + STLDeleteValues(&attached_shaders_); + STLDeleteValues(&attached_vframes_); + + // Destroy display + if (initialized_) + eglTerminate(display()); + + // Log error if this did not work + if (CheckEGLError("TearDown!")) + ALOGE("GLEnv: Error tearing down GL Environment!"); +} + +bool GLEnv::IsInitialized() const { + return (contexts_.size() > 0 && + surfaces_.size() > 0 && + display_ != EGL_NO_DISPLAY); +} + +bool GLEnv::Deactivate() { + eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + return !CheckEGLError("eglMakeCurrent"); +} + +bool GLEnv::Activate() { + ALOGV("Activate()"); + if (display() != eglGetCurrentDisplay() || + context() != eglGetCurrentContext() || + surface() != eglGetCurrentSurface(EGL_DRAW)) { + // Make sure we are initialized + if (context() == EGL_NO_CONTEXT || surface() == EGL_NO_SURFACE) + return false; + + // Make our context current + ALOGV("eglMakeCurrent"); + eglMakeCurrent(display(), surface(), surface(), context()); + + return !CheckEGLMakeCurrentError(); + } + return true; +} + +bool GLEnv::SwapBuffers() { + const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE; + return !CheckEGLError("eglSwapBuffers") && result; +} + +bool GLEnv::InitWithCurrentContext() { + if (IsInitialized()) + return true; + + display_ = eglGetCurrentDisplay(); + contexts_[0] = eglGetCurrentContext(); + surfaces_[0] = SurfaceWindowPair(eglGetCurrentSurface(EGL_DRAW), NULL); + + return (context() != EGL_NO_CONTEXT) && + (display() != EGL_NO_DISPLAY) && + (surface() != EGL_NO_SURFACE); +} + +bool GLEnv::InitWithNewContext() { + if (IsInitialized()) { + ALOGE("GLEnv: Attempting to reinitialize environment!"); + return false; + } + + display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (CheckEGLError("eglGetDisplay")) return false; + + EGLint majorVersion; + EGLint minorVersion; + eglInitialize(display(), &majorVersion, &minorVersion); + if (CheckEGLError("eglInitialize")) return false; + initialized_ = true; + + // Configure context/surface + EGLConfig config; + EGLint numConfigs = -1; + + // TODO(renn): Do we need the window bit here? + // TODO: Currently choosing the config that includes all + // This is not needed if the encoding is not being used + EGLint configAttribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RECORDABLE_ANDROID, EGL_TRUE, + EGL_NONE + }; + + eglChooseConfig(display(), configAttribs, &config, 1, &numConfigs); + if (numConfigs < 1) { + ALOGE("GLEnv::Init: No suitable EGL configuration found!"); + return false; + } + + // Create dummy surface using a SurfaceTexture + surfaceTexture_ = new SurfaceTexture(0); + window_ = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( + surfaceTexture_->getBufferQueue())); + + surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL); + if (CheckEGLError("eglCreateWindowSurface")) return false; + + // Create context + EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + contexts_[0] = eglCreateContext(display(), + config, + EGL_NO_CONTEXT, + context_attribs); + if (CheckEGLError("eglCreateContext")) return false; + + created_context_ = created_surface_ = true; + + return true; +} + +bool GLEnv::IsActive() const { + ALOGV("IsActive()"); + return context() == eglGetCurrentContext() + && display() == eglGetCurrentDisplay() + && surface() == eglGetCurrentSurface(EGL_DRAW); +} + +bool GLEnv::IsContextActive() const { + return context() == eglGetCurrentContext(); +} + +bool GLEnv::IsAnyContextActive() { + return eglGetCurrentContext() != EGL_NO_CONTEXT; +} + +int GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) { + const int id = ++max_surface_id_; + surfaces_[id] = SurfaceWindowPair(surface, window_handle); + return id; +} + +int GLEnv::AddSurface(const EGLSurface& surface) { + return AddWindowSurface(surface, NULL); +} + +bool GLEnv::SwitchToSurfaceId(int surface_id) { + ALOGV("SwitchToSurfaceId"); + if (surface_id_ != surface_id) { + const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id); + if (surface) { + bool wasActive = IsActive(); + surface_id_ = surface_id; + return wasActive ? Activate() : true; + } + return false; + } + return true; +} + +bool GLEnv::ReleaseSurfaceId(int surface_id) { + if (surface_id > 0) { + const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id); + if (surface_window_pair) { + if (surface_id_ == surface_id) + SwitchToSurfaceId(0); + eglDestroySurface(display(), surface_window_pair->first); + if (surface_window_pair->second) { + surface_window_pair->second->Destroy(); + delete surface_window_pair->second; + } + surfaces_.erase(surface_id); + return true; + } + } + return false; +} + +bool GLEnv::SetSurfaceTimestamp(int64_t timestamp) { + if (surface_id_ > 0) { + const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, + surface_id_); + if (surface_window_pair) { + ANativeWindow *window = static_cast<ANativeWindow*>( + surface_window_pair->second->InternalHandle()); + native_window_set_buffers_timestamp(window, timestamp); + return true; + } + } + return false; +} + +int GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) { + for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin(); + it != surfaces_.end(); + ++it) { + const WindowHandle* my_handle = it->second.second; + if (my_handle && my_handle->Equals(window_handle)) { + return it->first; + } + } + return -1; +} + + +int GLEnv::AddContext(const EGLContext& context) { + const int id = contexts_.size(); + contexts_[id] = context; + return id; +} + +bool GLEnv::SwitchToContextId(int context_id) { + const EGLContext* context = FindOrNull(contexts_, context_id); + if (context) { + if (context_id_ != context_id) { + context_id_ = context_id; + return Activate(); + } + return true; + } + return false; +} + +void GLEnv::ReleaseContextId(int context_id) { + if (context_id > 0) { + const EGLContext* context = FindOrNull(contexts_, context_id); + if (context) { + contexts_.erase(context_id); + if (context_id_ == context_id && IsActive()) + SwitchToContextId(0); + eglDestroyContext(display(), *context); + } + } +} + +bool GLEnv::CheckGLError(const std::string& op) { + bool err = false; + for (GLint error = glGetError(); error; error = glGetError()) { + ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n", + op.c_str(), + error); + err = true; + } + return err; +} + +bool GLEnv::CheckEGLError(const std::string& op) { + bool err = false; + for (EGLint error = eglGetError(); + error != EGL_SUCCESS; + error = eglGetError()) { + ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n", + op.c_str(), + error); + err = true; + } + return err; +} + +bool GLEnv::CheckEGLMakeCurrentError() { + bool err = false; + for (EGLint error = eglGetError(); + error != EGL_SUCCESS; + error = eglGetError()) { + switch (error) { + case EGL_BAD_DISPLAY: + ALOGE("EGL Error: Attempting to activate context with bad display!"); + break; + case EGL_BAD_SURFACE: + ALOGE("EGL Error: Attempting to activate context with bad surface!"); + break; + case EGL_BAD_ACCESS: + ALOGE("EGL Error: Attempting to activate context, which is " + "already active in another thread!"); + break; + default: + ALOGE("EGL Error: Making EGL rendering context current caused " + "error: 0x%x\n", error); + } + err = true; + } + return err; +} + +GLuint GLEnv::GetCurrentProgram() { + GLint result; + glGetIntegerv(GL_CURRENT_PROGRAM, &result); + ALOG_ASSERT(result >= 0); + return static_cast<GLuint>(result); +} + +EGLDisplay GLEnv::GetCurrentDisplay() { + return eglGetCurrentDisplay(); +} + +int GLEnv::NumberOfComponents(GLenum type) { + switch (type) { + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_BOOL_VEC3: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_FLOAT_MAT2: + return 4; + case GL_FLOAT_MAT3: + return 9; + case GL_FLOAT_MAT4: + return 16; + default: + return 0; + } +} + +void GLEnv::AttachShader(int key, ShaderProgram* shader) { + ShaderProgram* existingShader = ShaderWithKey(key); + if (existingShader) + delete existingShader; + attached_shaders_[key] = shader; +} + +void GLEnv::AttachVertexFrame(int key, VertexFrame* frame) { + VertexFrame* existingFrame = VertexFrameWithKey(key); + if (existingFrame) + delete existingFrame; + attached_vframes_[key] = frame; +} + +ShaderProgram* GLEnv::ShaderWithKey(int key) { + return FindPtrOrNull(attached_shaders_, key); +} + +VertexFrame* GLEnv::VertexFrameWithKey(int key) { + return FindPtrOrNull(attached_vframes_, key); +} + +} // namespace filterfw +} // namespace android |