165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/* 265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project 365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License"); 565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License. 665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at 765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * http://www.apache.org/licenses/LICENSE-2.0 965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software 1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS, 1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and 1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License. 1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// #define LOG_NDEBUG 0 1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "base/logging.h" 1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "base/utilities.h" 2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_env.h" 2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/shader_program.h" 2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/vertex_frame.h" 2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "system/window.h" 2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <map> 2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <string> 2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <EGL/eglext.h> 2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 29e3eae73abb5e429d9747f9c36ab025219e68bb26Mathias Agopian#include <gui/GLConsumer.h> 30e3eae73abb5e429d9747f9c36ab025219e68bb26Mathias Agopian 3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace android { 3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace filterfw { 3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLEnv::GLEnv() 3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn : display_(EGL_NO_DISPLAY), 3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn context_id_(0), 3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface_id_(0), 3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn max_surface_id_(0), 3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn created_context_(false), 4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn created_surface_(false), 4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn initialized_(false) { 4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLEnv::~GLEnv() { 4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Destroy surfaces 4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin(); 4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn it != surfaces_.end(); 4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ++it) { 4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (it->first != 0 || created_surface_) { 5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglDestroySurface(display(), it->second.first); 5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (it->second.second) { 5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn it->second.second->Destroy(); 5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn delete it->second.second; 5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Destroy contexts 5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (std::map<int, EGLContext>::iterator it = contexts_.begin(); 6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn it != contexts_.end(); 6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ++it) { 6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (it->first != 0 || created_context_) 6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglDestroyContext(display(), it->second); 6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Destroy attached shaders and frames 6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn STLDeleteValues(&attached_shaders_); 6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn STLDeleteValues(&attached_vframes_); 6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Destroy display 7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (initialized_) 7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglTerminate(display()); 7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Log error if this did not work 7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (CheckEGLError("TearDown!")) 7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("GLEnv: Error tearing down GL Environment!"); 7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::IsInitialized() const { 8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return (contexts_.size() > 0 && 8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaces_.size() > 0 && 8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn display_ != EGL_NO_DISPLAY); 8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::Deactivate() { 8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglMakeCurrent(display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return !CheckEGLError("eglMakeCurrent"); 8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::Activate() { 9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGV("Activate()"); 9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (display() != eglGetCurrentDisplay() || 9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn context() != eglGetCurrentContext() || 9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface() != eglGetCurrentSurface(EGL_DRAW)) { 9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Make sure we are initialized 9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context() == EGL_NO_CONTEXT || surface() == EGL_NO_SURFACE) 9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Make our context current 10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGV("eglMakeCurrent"); 10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglMakeCurrent(display(), surface(), surface(), context()); 10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return !CheckEGLMakeCurrentError(); 10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::SwapBuffers() { 10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const bool result = eglSwapBuffers(display(), surface()) == EGL_TRUE; 11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return !CheckEGLError("eglSwapBuffers") && result; 11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::InitWithCurrentContext() { 11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (IsInitialized()) 11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn display_ = eglGetCurrentDisplay(); 11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn contexts_[0] = eglGetCurrentContext(); 11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaces_[0] = SurfaceWindowPair(eglGetCurrentSurface(EGL_DRAW), NULL); 12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return (context() != EGL_NO_CONTEXT) && 12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn (display() != EGL_NO_DISPLAY) && 12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn (surface() != EGL_NO_SURFACE); 12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::InitWithNewContext() { 12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (IsInitialized()) { 12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("GLEnv: Attempting to reinitialize environment!"); 12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); 13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (CheckEGLError("eglGetDisplay")) return false; 13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLint majorVersion; 13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLint minorVersion; 13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglInitialize(display(), &majorVersion, &minorVersion); 13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (CheckEGLError("eglInitialize")) return false; 13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn initialized_ = true; 14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Configure context/surface 14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLConfig config; 14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLint numConfigs = -1; 14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // TODO(renn): Do we need the window bit here? 14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // TODO: Currently choosing the config that includes all 14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // This is not needed if the encoding is not being used 14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLint configAttribs[] = { 14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_RED_SIZE, 8, 15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_GREEN_SIZE, 8, 15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_BLUE_SIZE, 8, 15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_RECORDABLE_ANDROID, EGL_TRUE, 15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_NONE 15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglChooseConfig(display(), configAttribs, &config, 1, &numConfigs); 15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (numConfigs < 1) { 16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("GLEnv::Init: No suitable EGL configuration found!"); 16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 164d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden // Create dummy surface using a GLConsumer 165526f21b2c68bc7a386b6f3bebe2df4ca86170a0bDan Stoza sp<IGraphicBufferProducer> producer; 166526f21b2c68bc7a386b6f3bebe2df4ca86170a0bDan Stoza sp<IGraphicBufferConsumer> consumer; 167526f21b2c68bc7a386b6f3bebe2df4ca86170a0bDan Stoza BufferQueue::createBufferQueue(&producer, &consumer); 168ffdbe97f8e8e6381ab1c794c26386060acbc9bbeDan Stoza surfaceTexture_ = new GLConsumer(consumer, 0, GLConsumer::TEXTURE_EXTERNAL, 169ffdbe97f8e8e6381ab1c794c26386060acbc9bbeDan Stoza true, false); 170526f21b2c68bc7a386b6f3bebe2df4ca86170a0bDan Stoza window_ = new Surface(producer); 17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL); 17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (CheckEGLError("eglCreateWindowSurface")) return false; 17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Create context 17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn contexts_[0] = eglCreateContext(display(), 17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn config, 17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn EGL_NO_CONTEXT, 18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn context_attribs); 18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (CheckEGLError("eglCreateContext")) return false; 18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn created_context_ = created_surface_ = true; 18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::IsActive() const { 18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGV("IsActive()"); 19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return context() == eglGetCurrentContext() 19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn && display() == eglGetCurrentDisplay() 19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn && surface() == eglGetCurrentSurface(EGL_DRAW); 19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::IsContextActive() const { 19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return context() == eglGetCurrentContext(); 19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::IsAnyContextActive() { 20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return eglGetCurrentContext() != EGL_NO_CONTEXT; 20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLEnv::AddWindowSurface(const EGLSurface& surface, WindowHandle* window_handle) { 20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const int id = ++max_surface_id_; 20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaces_[id] = SurfaceWindowPair(surface, window_handle); 20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return id; 20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLEnv::AddSurface(const EGLSurface& surface) { 21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return AddWindowSurface(surface, NULL); 21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::SwitchToSurfaceId(int surface_id) { 21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGV("SwitchToSurfaceId"); 21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_id_ != surface_id) { 21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const SurfaceWindowPair* surface = FindOrNull(surfaces_, surface_id); 21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface) { 21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn bool wasActive = IsActive(); 21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface_id_ = surface_id; 22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return wasActive ? Activate() : true; 22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::ReleaseSurfaceId(int surface_id) { 22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_id > 0) { 22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, surface_id); 23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_window_pair) { 23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_id_ == surface_id) 23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn SwitchToSurfaceId(0); 23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglDestroySurface(display(), surface_window_pair->first); 23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_window_pair->second) { 23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface_window_pair->second->Destroy(); 23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn delete surface_window_pair->second; 23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaces_.erase(surface_id); 23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::SetSurfaceTimestamp(int64_t timestamp) { 24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_id_ > 0) { 24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const SurfaceWindowPair* surface_window_pair = FindOrNull(surfaces_, 24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface_id_); 24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (surface_window_pair) { 25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ANativeWindow *window = static_cast<ANativeWindow*>( 25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface_window_pair->second->InternalHandle()); 25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn native_window_set_buffers_timestamp(window, timestamp); 25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLEnv::FindSurfaceIdForWindow(const WindowHandle* window_handle) { 26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (std::map<int, SurfaceWindowPair>::iterator it = surfaces_.begin(); 26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn it != surfaces_.end(); 26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ++it) { 26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const WindowHandle* my_handle = it->second.second; 26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (my_handle && my_handle->Equals(window_handle)) { 26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return it->first; 26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return -1; 26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLEnv::AddContext(const EGLContext& context) { 27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const int id = contexts_.size(); 27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn contexts_[id] = context; 27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return id; 27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::SwitchToContextId(int context_id) { 27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const EGLContext* context = FindOrNull(contexts_, context_id); 28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context) { 28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context_id_ != context_id) { 28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn context_id_ = context_id; 28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return Activate(); 28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return false; 28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid GLEnv::ReleaseContextId(int context_id) { 29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context_id > 0) { 29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn const EGLContext* context = FindOrNull(contexts_, context_id); 29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context) { 29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn contexts_.erase(context_id); 29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (context_id_ == context_id && IsActive()) 29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn SwitchToContextId(0); 29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn eglDestroyContext(display(), *context); 29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::CheckGLError(const std::string& op) { 30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn bool err = false; 30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (GLint error = glGetError(); error; error = glGetError()) { 30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("GL Error: Operation '%s' caused GL error (0x%x)\n", 30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn op.c_str(), 30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error); 30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn err = true; 30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return err; 31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::CheckEGLError(const std::string& op) { 31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn bool err = false; 31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (EGLint error = eglGetError(); 31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error != EGL_SUCCESS; 31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error = eglGetError()) { 31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("EGL Error: Operation '%s' caused EGL error (0x%x)\n", 31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn op.c_str(), 32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error); 32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn err = true; 32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return err; 32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLEnv::CheckEGLMakeCurrentError() { 32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn bool err = false; 32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn for (EGLint error = eglGetError(); 32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error != EGL_SUCCESS; 33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn error = eglGetError()) { 33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn switch (error) { 33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case EGL_BAD_DISPLAY: 33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("EGL Error: Attempting to activate context with bad display!"); 33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case EGL_BAD_SURFACE: 33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("EGL Error: Attempting to activate context with bad surface!"); 33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case EGL_BAD_ACCESS: 33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("EGL Error: Attempting to activate context, which is " 34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "already active in another thread!"); 34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn default: 34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOGE("EGL Error: Making EGL rendering context current caused " 34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "error: 0x%x\n", error); 34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn err = true; 34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return err; 34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint GLEnv::GetCurrentProgram() { 35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn GLint result; 35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn glGetIntegerv(GL_CURRENT_PROGRAM, &result); 35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ALOG_ASSERT(result >= 0); 35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return static_cast<GLuint>(result); 35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennEGLDisplay GLEnv::GetCurrentDisplay() { 35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return eglGetCurrentDisplay(); 36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLEnv::NumberOfComponents(GLenum type) { 36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn switch (type) { 36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_BOOL: 36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT: 36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_INT: 36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 1; 36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_BOOL_VEC2: 36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_VEC2: 37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_INT_VEC2: 37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 2; 37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_INT_VEC3: 37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_VEC3: 37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_BOOL_VEC3: 37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 3; 37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_BOOL_VEC4: 37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_VEC4: 37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_INT_VEC4: 37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_MAT2: 38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 4; 38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_MAT3: 38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 9; 38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case GL_FLOAT_MAT4: 38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 16; 38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn default: 38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return 0; 38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid GLEnv::AttachShader(int key, ShaderProgram* shader) { 39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn ShaderProgram* existingShader = ShaderWithKey(key); 39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (existingShader) 39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn delete existingShader; 39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn attached_shaders_[key] = shader; 39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid GLEnv::AttachVertexFrame(int key, VertexFrame* frame) { 39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn VertexFrame* existingFrame = VertexFrameWithKey(key); 39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (existingFrame) 40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn delete existingFrame; 40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn attached_vframes_[key] = frame; 40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram* GLEnv::ShaderWithKey(int key) { 40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return FindPtrOrNull(attached_shaders_, key); 40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennVertexFrame* GLEnv::VertexFrameWithKey(int key) { 40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return FindPtrOrNull(attached_vframes_, key); 41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace filterfw 41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace android 414