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