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
1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "base/logging.h"
1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_env.h"
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_frame.h"
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/shader_program.h"
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <vector>
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace android {
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace filterfw {
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic const int kIdentityShaderKey = 1;
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn//
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// A GLFrame stores pixel data on the GPU. It uses two kinds of GL data
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// containers for this: Textures and Frame Buffer Objects (FBOs). Textures are
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// used whenever pixel data needs to be read into a shader or the host program,
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// and when pixel data is uploaded to a GLFrame. The FBO is used as a rendering
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// target for shaders.
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn//
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLFrame::GLFrame(GLEnv* gl_env)
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : gl_env_(gl_env),
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    width_(0),
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    height_(0),
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vp_x_(0),
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vp_y_(0),
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vp_width_(0),
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vp_height_(0),
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    texture_id_(0),
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fbo_id_(0),
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    texture_target_(GL_TEXTURE_2D),
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    texture_state_(kStateUninitialized),
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fbo_state_(kStateUninitialized),
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owns_texture_(false),
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owns_fbo_(false) {
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetDefaultTexParameters();
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::Init(int width, int height) {
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we haven't been initialized already
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (width_ == 0 && height_ == 0) {
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    InitDimensions(width, height);
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::InitWithTexture(GLint texture_id, int width, int height) {
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  texture_id_ = texture_id;
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  texture_state_ = glIsTexture(texture_id) ? kStateComplete : kStateGenerated;
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  InitDimensions(width, height);
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::InitWithFbo(GLint fbo_id, int width, int height) {
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  fbo_id_ = fbo_id;
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  fbo_state_ = glIsFramebuffer(fbo_id) ? kStateComplete : kStateGenerated;
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  texture_state_ = kStateUnmanaged;
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  InitDimensions(width, height);
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::InitWithExternalTexture() {
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  texture_target_ = GL_TEXTURE_EXTERNAL_OES;
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  width_ = 0;
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  height_ = 0;
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return GenerateTextureName();
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid GLFrame::InitDimensions(int width, int height) {
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  width_ = width;
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  height_ = height;
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_width_ = width;
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_height_ = height;
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLFrame::~GLFrame() {
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete texture
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (owns_texture_) {
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Bind FBO so that texture is unbound from it during deletion
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (fbo_state_ == kStateComplete) {
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glDeleteTextures(1, &texture_id_);
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete FBO
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (owns_fbo_) {
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glDeleteFramebuffers(1, &fbo_id_);
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::GenerateMipMap() {
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (FocusTexture()) {
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGenerateMipmap(GL_TEXTURE_2D);
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Generating MipMap!");
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::SetTextureParameter(GLenum pname, GLint value) {
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (value != tex_params_[pname]) {
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (FocusTexture()) {
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glTexParameteri(GL_TEXTURE_2D, pname, value);
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (!GLEnv::CheckGLError("Setting texture parameter!")) {
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        tex_params_[pname] = value;
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return true;
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else {
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::UpdateTexParameters() {
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_params_[GL_TEXTURE_MAG_FILTER]);
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_params_[GL_TEXTURE_MIN_FILTER]);
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex_params_[GL_TEXTURE_WRAP_S]);
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex_params_[GL_TEXTURE_WRAP_T]);
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return !GLEnv::CheckGLError("Resetting texture parameters!");
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::TexParametersModifed() {
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return tex_params_[GL_TEXTURE_MAG_FILTER] != GL_LINEAR
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ||   tex_params_[GL_TEXTURE_MIN_FILTER] != GL_LINEAR
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ||   tex_params_[GL_TEXTURE_WRAP_S] != GL_CLAMP_TO_EDGE
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ||   tex_params_[GL_TEXTURE_WRAP_T] != GL_CLAMP_TO_EDGE;
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid GLFrame::SetDefaultTexParameters() {
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_params_[GL_TEXTURE_MAG_FILTER] = GL_LINEAR;
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_params_[GL_TEXTURE_MIN_FILTER] = GL_LINEAR;
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_params_[GL_TEXTURE_WRAP_S] = GL_CLAMP_TO_EDGE;
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_params_[GL_TEXTURE_WRAP_T] = GL_CLAMP_TO_EDGE;
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::ResetTexParameters() {
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (TexParametersModifed()) {
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (BindTexture()) {
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      SetDefaultTexParameters();
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return UpdateTexParameters();
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::CopyDataTo(uint8_t* buffer, int size) {
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return (size >= Size())
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ? CopyPixelsTo(buffer)
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    : false;
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::CopyPixelsTo(uint8_t* buffer) {
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Use one of the pixel reading methods below, ordered from most
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // efficient to least efficient.
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ == kStateComplete)
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return ReadFboPixels(buffer);
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else if (texture_state_ == kStateComplete)
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return ReadTexturePixels(buffer);
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::WriteData(const uint8_t* data, int data_size) {
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return (data_size == Size()) ? UploadTexturePixels(data) : false;
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::SetViewport(int x, int y, int width, int height) {
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_x_ = x;
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_y_ = y;
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_width_ = width;
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vp_height_ = height;
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLFrame* GLFrame::Clone() const {
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLFrame* target = new GLFrame(gl_env_);
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target->Init(width_, height_);
19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target->CopyPixelsFrom(this);
19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return target;
20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::CopyPixelsFrom(const GLFrame* frame) {
20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (frame == this) {
20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (frame && frame->width_ == width_ && frame->height_ == height_) {
20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    std::vector<const GLFrame*> sources;
20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    sources.push_back(frame);
20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GetIdentity()->Process(sources, this);
20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint GLFrame::Size() const {
21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return width_ * height_ * 4;
21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram* GLFrame::GetIdentity() const {
21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ShaderProgram* stored_shader = gl_env_->ShaderWithKey(kIdentityShaderKey);
22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!stored_shader) {
22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    stored_shader = ShaderProgram::CreateIdentity(gl_env_);
22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    gl_env_->AttachShader(kIdentityShaderKey, stored_shader);
22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return stored_shader;
22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::BindFrameBuffer() const {
22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind the FBO
22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::CheckGLError("FBO Binding")) return false;
23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Set viewport
23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glViewport(vp_x_, vp_y_, vp_width_, vp_height_);
23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::CheckGLError("ViewPort Setup")) return false;
23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::FocusFrameBuffer() {
24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create texture backing if necessary
24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (texture_state_ == kStateUninitialized) {
24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!GenerateTextureName())
24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create and bind FBO to texture if necessary
24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ != kStateComplete) {
24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!GenerateFboName() || !AttachTextureToFbo())
24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // And bind it.
25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return BindFrameBuffer();
25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::BindTexture() const {
25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindTexture(GL_TEXTURE_2D, texture_id_);
25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return !GLEnv::CheckGLError("Texture Binding");
25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint GLFrame::GetTextureId() const {
26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return texture_id_;
26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Returns the held FBO id. Only call this if the GLFrame holds an FBO. You
26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// can check this by calling HoldsFbo().
26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint GLFrame::GetFboId() const {
26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return fbo_id_;
26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::FocusTexture() {
27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we have a texture
27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!GenerateTextureName())
27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind the texture
27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!BindTexture())
27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return !GLEnv::CheckGLError("Texture Binding");
28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::GenerateTextureName() {
28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (texture_state_ == kStateUninitialized) {
28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Make sure texture not in use already
28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (glIsTexture(texture_id_)) {
28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("GLFrame: Cannot generate texture id %d, as it is in use already!", texture_id_);
28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Generate the texture
29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGenTextures (1, &texture_id_);
29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Texture Generation"))
29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    texture_state_ = kStateGenerated;
29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owns_texture_ = true;
29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::AllocateTexture() {
30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Allocate or re-allocate (if texture was deleted externally).
30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (texture_state_ == kStateGenerated || TextureWasDeleted()) {
30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("GLFrame: Allocating texture: %d", texture_id_);
30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindTexture(GL_TEXTURE_2D, texture_id_);
30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glTexImage2D(GL_TEXTURE_2D,
30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               0,
30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               GL_RGBA,
31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               width_,
31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               height_,
31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               0,
31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               GL_RGBA,
31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               GL_UNSIGNED_BYTE,
31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               NULL);
31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!GLEnv::CheckGLError("Texture Allocation")) {
31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      UpdateTexParameters();
31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      texture_state_ = kStateComplete;
31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return texture_state_ == kStateComplete;
32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::TextureWasDeleted() const {
32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return texture_state_ == kStateComplete && !glIsTexture(texture_id_);
32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::GenerateFboName() {
32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ == kStateUninitialized) {
33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Make sure FBO not in use already
33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (glIsFramebuffer(fbo_id_)) {
33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("GLFrame: Cannot generate FBO id %d, as it is in use already!", fbo_id_);
33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Create FBO
33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGenFramebuffers(1, &fbo_id_);
33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("FBO Generation"))
33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fbo_state_ = kStateGenerated;
34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owns_fbo_ = true;
34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::ReadFboPixels(uint8_t* pixels) const {
34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ == kStateComplete) {
34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    BindFrameBuffer();
35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glReadPixels(0,
35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 0,
35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 width_,
35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 height_,
35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 GL_RGBA,
35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 GL_UNSIGNED_BYTE,
35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 pixels);
35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("FBO Pixel Readout");
35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::ReadTexturePixels(uint8_t* pixels) const {
36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Read pixels from texture if we do not have an FBO
36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // NOTE: OpenGL ES does NOT support glGetTexImage() for reading out texture
36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // data. The only way for us to get texture data is to create a new FBO and
36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // render the current texture frame into it. As this is quite inefficient,
36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // and unnecessary (this can only happen if the user is reading out data
36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // that was just set, and not run through a filter), we warn the user about
36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // this here.
37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ALOGW("Warning: Reading pixel data from unfiltered GL frame. This is highly "
37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        "inefficient. Please consider using your original pixel buffer "
37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        "instead!");
37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create source frame set (unfortunately this requires an ugly const-cast,
37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // as we need to wrap ourselves in a frame-set. Still, as this set is used
37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // as input only, we are certain we will not be modified).
37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<const GLFrame*> sources;
37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  sources.push_back(this);
37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create target frame
38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLFrame target(gl_env_);
38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target.Init(width_, height_);
38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Render the texture to the target
38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GetIdentity()->Process(sources, &target);
38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Get the pixel data
38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return target.ReadFboPixels(pixels);
38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::AttachTextureToFbo() {
39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Check FBO and texture state. We do not do anything if we are not managing the texture.
39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ == kStateComplete || texture_state_ == kStateUnmanaged) {
39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (fbo_state_ != kStateGenerated) {
39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Attempting to attach texture to FBO with no FBO in place!");
39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // If texture has been generated, make sure it is allocated.
40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!AllocateTexture())
40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind the frame buffer, and check if we it is already bound
40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind the texture to the frame buffer
40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  LOG_FRAME("Attaching tex %d w %d h %d to fbo %d", texture_id_, width_, height_, fbo_id_);
40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glFramebufferTexture2D(GL_FRAMEBUFFER,
41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                         GL_COLOR_ATTACHMENT0,
41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                         GL_TEXTURE_2D,
41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                         texture_id_,
41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                         0);
41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Cleanup
41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindTexture(GL_TEXTURE_2D, 0);
41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindFramebuffer(GL_FRAMEBUFFER, 0);
41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::CheckGLError("Texture Binding to FBO"))
42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else
42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fbo_state_ = kStateComplete;
42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::ReattachTextureToFbo() {
42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return (fbo_state_ == kStateGenerated) ? AttachTextureToFbo() : true;
42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::DetachTextureFromFbo() {
43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (fbo_state_ == kStateComplete && texture_state_ == kStateComplete) {
43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("Detaching tex %d w %d h %d from fbo %d", texture_id_, width_, height_, fbo_id_);
43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glFramebufferTexture2D(GL_FRAMEBUFFER,
43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           GL_COLOR_ATTACHMENT0,
43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           GL_TEXTURE_2D,
43865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           0,
43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                           0);
44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Detaching texture to FBO"))
44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    else
44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      fbo_state_ = kStateGenerated;
44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool GLFrame::UploadTexturePixels(const uint8_t* pixels) {
44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind the texture object
45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  FocusTexture();
45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Load mipmap level 0
45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_,
45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn               0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Set the user specified texture parameters
45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  UpdateTexParameters();
45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::CheckGLError("Texture Pixel Upload"))
46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
46165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
46265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  texture_state_ = kStateComplete;
46365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
46465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
46565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace filterfw
46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace android
468