130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni/*
230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Copyright (C) 2011 The Android Open Source Project
330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Licensed under the Apache License, Version 2.0 (the "License");
530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * you may not use this file except in compliance with the License.
630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * You may obtain a copy of the License at
730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *      http://www.apache.org/licenses/LICENSE-2.0
930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni *
1030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * Unless required by applicable law or agreed to in writing, software
1130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * distributed under the License is distributed on an "AS IS" BASIS,
1230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * See the License for the specific language governing permissions and
1430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni * limitations under the License.
1530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni */
1630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni#include "base/logging.h"
1830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
1930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni#include "core/gl_env.h"
2030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni#include "core/gl_frame.h"
2130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni#include "core/shader_program.h"
2230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
23e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala#include <vector>
24e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala
2530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroninamespace android {
2630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroninamespace filterfw {
2730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
28511360e61650864ea22a171159efe073c80d0cdbMarius Rennstatic const int kIdentityShaderKey = 1;
29511360e61650864ea22a171159efe073c80d0cdbMarius Renn
3030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni//
3130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// A GLFrame stores pixel data on the GPU. It uses two kinds of GL data
3230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// containers for this: Textures and Frame Buffer Objects (FBOs). Textures are
3330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// used whenever pixel data needs to be read into a shader or the host program,
3430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// and when pixel data is uploaded to a GLFrame. The FBO is used as a rendering
3530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// target for shaders.
3630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni//
3730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
38511360e61650864ea22a171159efe073c80d0cdbMarius RennGLFrame::GLFrame(GLEnv* gl_env)
39511360e61650864ea22a171159efe073c80d0cdbMarius Renn  : gl_env_(gl_env),
40511360e61650864ea22a171159efe073c80d0cdbMarius Renn    width_(0),
4130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    height_(0),
4230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    vp_x_(0),
4330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    vp_y_(0),
4430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    vp_width_(0),
4530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    vp_height_(0),
4630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    texture_id_(0),
4730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    fbo_id_(0),
4830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    texture_target_(GL_TEXTURE_2D),
4930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    texture_state_(kStateUninitialized),
5030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    fbo_state_(kStateUninitialized),
51776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    owns_texture_(false),
52776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    owns_fbo_(false) {
53f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  SetDefaultTexParameters();
5430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::Init(int width, int height) {
5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Make sure we haven't been initialized already
5830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (width_ == 0 && height_ == 0) {
5930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    InitDimensions(width, height);
6030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return true;
6130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
6230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return false;
6330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
6430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
65776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Rennbool GLFrame::InitWithTexture(GLint texture_id, int width, int height) {
6630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  texture_id_ = texture_id;
67776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  texture_state_ = glIsTexture(texture_id) ? kStateComplete : kStateGenerated;
6830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  InitDimensions(width, height);
6930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
7030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
7130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
72776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Rennbool GLFrame::InitWithFbo(GLint fbo_id, int width, int height) {
7330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  fbo_id_ = fbo_id;
74776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  fbo_state_ = glIsFramebuffer(fbo_id) ? kStateComplete : kStateGenerated;
7592568796d043c794553e5bcaa797c906899e71f0Marius Renn  texture_state_ = kStateUnmanaged;
7630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  InitDimensions(width, height);
7730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
7830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
7930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
8030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::InitWithExternalTexture() {
8130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  texture_target_ = GL_TEXTURE_EXTERNAL_OES;
8230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  width_ = 0;
8330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  height_ = 0;
8492568796d043c794553e5bcaa797c906899e71f0Marius Renn  return GenerateTextureName();
8530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
8630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
8730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronivoid GLFrame::InitDimensions(int width, int height) {
8830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  width_ = width;
8930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  height_ = height;
9030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_width_ = width;
9130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_height_ = height;
9230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
9330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
9430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLFrame::~GLFrame() {
95776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  // Delete texture
96776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  if (owns_texture_) {
97776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    // Bind FBO so that texture is unbound from it during deletion
98776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    if (fbo_state_ == kStateComplete) {
99776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn      glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
100776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    }
101776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    glDeleteTextures(1, &texture_id_);
102776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  }
103776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn
104776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  // Delete FBO
105776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  if (owns_fbo_) {
106776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    glDeleteFramebuffers(1, &fbo_id_);
10730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
10830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
10930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
11030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::GenerateMipMap() {
111fb7c020acdd0fb38c9d2b6750d904b64cc78458dWei Hua  if (FocusTexture()) {
11230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    glGenerateMipmap(GL_TEXTURE_2D);
11330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return !GLEnv::CheckGLError("Generating MipMap!");
11430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
11530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return false;
11630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
11730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
11830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::SetTextureParameter(GLenum pname, GLint value) {
119f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  if (value != tex_params_[pname]) {
120f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    if (FocusTexture()) {
121f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn      glTexParameteri(GL_TEXTURE_2D, pname, value);
122f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn      if (!GLEnv::CheckGLError("Setting texture parameter!")) {
123f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        tex_params_[pname] = value;
124f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn        return true;
125f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn      }
126f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    }
127f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  } else {
128f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    return true;
12930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
13030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return false;
13130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
13230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
133f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Rennbool GLFrame::UpdateTexParameters() {
134f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_params_[GL_TEXTURE_MAG_FILTER]);
135f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_params_[GL_TEXTURE_MIN_FILTER]);
136f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex_params_[GL_TEXTURE_WRAP_S]);
137f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex_params_[GL_TEXTURE_WRAP_T]);
138f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  return !GLEnv::CheckGLError("Resetting texture parameters!");
139f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn}
140f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
141f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Rennbool GLFrame::TexParametersModifed() {
142f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  return tex_params_[GL_TEXTURE_MAG_FILTER] != GL_LINEAR
143f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    ||   tex_params_[GL_TEXTURE_MIN_FILTER] != GL_LINEAR
144f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    ||   tex_params_[GL_TEXTURE_WRAP_S] != GL_CLAMP_TO_EDGE
145f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    ||   tex_params_[GL_TEXTURE_WRAP_T] != GL_CLAMP_TO_EDGE;
146f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn}
147f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
148f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Rennvoid GLFrame::SetDefaultTexParameters() {
149f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  tex_params_[GL_TEXTURE_MAG_FILTER] = GL_LINEAR;
150f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  tex_params_[GL_TEXTURE_MIN_FILTER] = GL_LINEAR;
151f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  tex_params_[GL_TEXTURE_WRAP_S] = GL_CLAMP_TO_EDGE;
152f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  tex_params_[GL_TEXTURE_WRAP_T] = GL_CLAMP_TO_EDGE;
153f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn}
154f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn
155f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Rennbool GLFrame::ResetTexParameters() {
156f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  if (TexParametersModifed()) {
15733164fee278e106cc5d0493a1c184f208e9d273fMarius Renn    if (BindTexture()) {
158f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn      SetDefaultTexParameters();
159f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn      return UpdateTexParameters();
16033164fee278e106cc5d0493a1c184f208e9d273fMarius Renn    }
161f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn    return false;
16233164fee278e106cc5d0493a1c184f208e9d273fMarius Renn  }
163f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  return true;
16433164fee278e106cc5d0493a1c184f208e9d273fMarius Renn}
16533164fee278e106cc5d0493a1c184f208e9d273fMarius Renn
166e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::CopyDataTo(uint8_t* buffer, int size) {
16730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return (size >= Size())
16830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    ? CopyPixelsTo(buffer)
16930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    : false;
17030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
17130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
172e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::CopyPixelsTo(uint8_t* buffer) {
17315ebdcc40023b94f8f7184b8c4ea47acc8d207c6Marius Renn  // Use one of the pixel reading methods below, ordered from most
17415ebdcc40023b94f8f7184b8c4ea47acc8d207c6Marius Renn  // efficient to least efficient.
17515ebdcc40023b94f8f7184b8c4ea47acc8d207c6Marius Renn  if (fbo_state_ == kStateComplete)
17630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return ReadFboPixels(buffer);
17715ebdcc40023b94f8f7184b8c4ea47acc8d207c6Marius Renn  else if (texture_state_ == kStateComplete)
17815ebdcc40023b94f8f7184b8c4ea47acc8d207c6Marius Renn    return ReadTexturePixels(buffer);
17930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  else
18030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
18130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
18230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
183e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::WriteData(const uint8_t* data, int data_size) {
18430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return (data_size == Size()) ? UploadTexturePixels(data) : false;
18530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
18630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
18730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::SetViewport(int x, int y, int width, int height) {
18830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_x_ = x;
18930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_y_ = y;
19030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_width_ = width;
19130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  vp_height_ = height;
19230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
19330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
19430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
19530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLFrame* GLFrame::Clone() const {
196511360e61650864ea22a171159efe073c80d0cdbMarius Renn  GLFrame* target = new GLFrame(gl_env_);
19730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  target->Init(width_, height_);
19830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  target->CopyPixelsFrom(this);
19930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return target;
20030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
20130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
20230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::CopyPixelsFrom(const GLFrame* frame) {
20330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (frame == this) {
20430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return true;
20530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  } else if (frame && frame->width_ == width_ && frame->height_ == height_) {
206e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala    std::vector<const GLFrame*> sources;
20730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    sources.push_back(frame);
20830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    GetIdentity()->Process(sources, this);
20930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return true;
21030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
21130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return false;
21230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
21330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
21430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniint GLFrame::Size() const {
21530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return width_ * height_ * 4;
21630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
21730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
21830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniShaderProgram* GLFrame::GetIdentity() const {
219511360e61650864ea22a171159efe073c80d0cdbMarius Renn  ShaderProgram* stored_shader = gl_env_->ShaderWithKey(kIdentityShaderKey);
220511360e61650864ea22a171159efe073c80d0cdbMarius Renn  if (!stored_shader) {
221511360e61650864ea22a171159efe073c80d0cdbMarius Renn    stored_shader = ShaderProgram::CreateIdentity(gl_env_);
222511360e61650864ea22a171159efe073c80d0cdbMarius Renn    gl_env_->AttachShader(kIdentityShaderKey, stored_shader);
223511360e61650864ea22a171159efe073c80d0cdbMarius Renn  }
224511360e61650864ea22a171159efe073c80d0cdbMarius Renn  return stored_shader;
22530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
22630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
22730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::BindFrameBuffer() const {
22830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Bind the FBO
22930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
23030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (GLEnv::CheckGLError("FBO Binding")) return false;
23130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
23230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Set viewport
23330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glViewport(vp_x_, vp_y_, vp_width_, vp_height_);
23430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (GLEnv::CheckGLError("ViewPort Setup")) return false;
23530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
23630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
23730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
23830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
23930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::FocusFrameBuffer() {
24030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Create texture backing if necessary
24130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (texture_state_ == kStateUninitialized) {
24292568796d043c794553e5bcaa797c906899e71f0Marius Renn    if (!GenerateTextureName())
24330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
24430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
24530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
24630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Create and bind FBO to texture if necessary
247776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  if (fbo_state_ != kStateComplete) {
24892568796d043c794553e5bcaa797c906899e71f0Marius Renn    if (!GenerateFboName() || !AttachTextureToFbo())
24930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
25030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
25130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
25230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // And bind it.
25330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return BindFrameBuffer();
25430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
25530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
25630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::BindTexture() const {
25730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glBindTexture(GL_TEXTURE_2D, texture_id_);
25830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return !GLEnv::CheckGLError("Texture Binding");
25930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
26030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
26130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLuint GLFrame::GetTextureId() const {
26230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return texture_id_;
26330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
26430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
26530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// Returns the held FBO id. Only call this if the GLFrame holds an FBO. You
26630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// can check this by calling HoldsFbo().
26730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLuint GLFrame::GetFboId() const {
26830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return fbo_id_;
26930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
27030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
27130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::FocusTexture() {
27230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Make sure we have a texture
27392568796d043c794553e5bcaa797c906899e71f0Marius Renn  if (!GenerateTextureName())
27430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
27530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
27630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Bind the texture
27730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (!BindTexture())
27830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
27930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
28030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return !GLEnv::CheckGLError("Texture Binding");
28130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
28230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
28392568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::GenerateTextureName() {
28430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (texture_state_ == kStateUninitialized) {
28530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    // Make sure texture not in use already
28630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    if (glIsTexture(texture_id_)) {
28730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      LOGE("GLFrame: Cannot generate texture id %d, as it is in use already!", texture_id_);
28830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
28930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
29030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
29130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    // Generate the texture
29230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    glGenTextures (1, &texture_id_);
29330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    if (GLEnv::CheckGLError("Texture Generation"))
29430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
29530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    texture_state_ = kStateGenerated;
296776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    owns_texture_ = true;
29730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
29830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
29930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
30030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
30130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
30292568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::AllocateTexture() {
30392568796d043c794553e5bcaa797c906899e71f0Marius Renn  // Allocate or re-allocate (if texture was deleted externally).
30492568796d043c794553e5bcaa797c906899e71f0Marius Renn  if (texture_state_ == kStateGenerated || TextureWasDeleted()) {
30592568796d043c794553e5bcaa797c906899e71f0Marius Renn    LOG_FRAME("GLFrame: Allocating texture: %d", texture_id_);
30692568796d043c794553e5bcaa797c906899e71f0Marius Renn    glBindTexture(GL_TEXTURE_2D, texture_id_);
30792568796d043c794553e5bcaa797c906899e71f0Marius Renn    glTexImage2D(GL_TEXTURE_2D,
30892568796d043c794553e5bcaa797c906899e71f0Marius Renn               0,
30992568796d043c794553e5bcaa797c906899e71f0Marius Renn               GL_RGBA,
31092568796d043c794553e5bcaa797c906899e71f0Marius Renn               width_,
31192568796d043c794553e5bcaa797c906899e71f0Marius Renn               height_,
31292568796d043c794553e5bcaa797c906899e71f0Marius Renn               0,
31392568796d043c794553e5bcaa797c906899e71f0Marius Renn               GL_RGBA,
31492568796d043c794553e5bcaa797c906899e71f0Marius Renn               GL_UNSIGNED_BYTE,
31592568796d043c794553e5bcaa797c906899e71f0Marius Renn               NULL);
31692568796d043c794553e5bcaa797c906899e71f0Marius Renn    if (!GLEnv::CheckGLError("Texture Allocation")) {
31792568796d043c794553e5bcaa797c906899e71f0Marius Renn      UpdateTexParameters();
31892568796d043c794553e5bcaa797c906899e71f0Marius Renn      texture_state_ = kStateComplete;
31992568796d043c794553e5bcaa797c906899e71f0Marius Renn    }
32092568796d043c794553e5bcaa797c906899e71f0Marius Renn  }
32192568796d043c794553e5bcaa797c906899e71f0Marius Renn  return texture_state_ == kStateComplete;
32292568796d043c794553e5bcaa797c906899e71f0Marius Renn}
32392568796d043c794553e5bcaa797c906899e71f0Marius Renn
32492568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::TextureWasDeleted() const {
32592568796d043c794553e5bcaa797c906899e71f0Marius Renn  return texture_state_ == kStateComplete && !glIsTexture(texture_id_);
32692568796d043c794553e5bcaa797c906899e71f0Marius Renn}
32792568796d043c794553e5bcaa797c906899e71f0Marius Renn
32892568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::GenerateFboName() {
32930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (fbo_state_ == kStateUninitialized) {
33030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    // Make sure FBO not in use already
33130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    if (glIsFramebuffer(fbo_id_)) {
33230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      LOGE("GLFrame: Cannot generate FBO id %d, as it is in use already!", fbo_id_);
33330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
33430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    }
33530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
33630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    // Create FBO
33730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    glGenFramebuffers(1, &fbo_id_);
33830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    if (GLEnv::CheckGLError("FBO Generation"))
33930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni      return false;
34030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    fbo_state_ = kStateGenerated;
341776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn    owns_fbo_ = true;
34230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
34330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
34430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
34530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
34630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
347e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::ReadFboPixels(uint8_t* pixels) const {
348776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  if (fbo_state_ == kStateComplete) {
34930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    BindFrameBuffer();
35030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    glReadPixels(0,
35130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 0,
35230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 width_,
35330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 height_,
35430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 GL_RGBA,
35530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 GL_UNSIGNED_BYTE,
35630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni                 pixels);
35730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return !GLEnv::CheckGLError("FBO Pixel Readout");
35830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  }
35930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return false;
36030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
36130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
362e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::ReadTexturePixels(uint8_t* pixels) const {
36330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Read pixels from texture if we do not have an FBO
36430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // NOTE: OpenGL ES does NOT support glGetTexImage() for reading out texture
36530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // data. The only way for us to get texture data is to create a new FBO and
36630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // render the current texture frame into it. As this is quite inefficient,
36730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // and unnecessary (this can only happen if the user is reading out data
36830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // that was just set, and not run through a filter), we warn the user about
36930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // this here.
37030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  LOGW("Warning: Reading pixel data from unfiltered GL frame. This is highly "
37130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni       "inefficient. Please consider using your original pixel buffer "
37230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni       "instead!");
37330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
37430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Create source frame set (unfortunately this requires an ugly const-cast,
37530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // as we need to wrap ourselves in a frame-set. Still, as this set is used
37630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // as input only, we are certain we will not be modified).
377e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala  std::vector<const GLFrame*> sources;
37830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  sources.push_back(this);
37930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
38030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Create target frame
381511360e61650864ea22a171159efe073c80d0cdbMarius Renn  GLFrame target(gl_env_);
38230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  target.Init(width_, height_);
38330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
38430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Render the texture to the target
38530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  GetIdentity()->Process(sources, &target);
38630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
38730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Get the pixel data
38830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return target.ReadFboPixels(pixels);
38930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
39030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
39192568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::AttachTextureToFbo() {
39292568796d043c794553e5bcaa797c906899e71f0Marius Renn  // Check FBO and texture state. We do not do anything if we are not managing the texture.
39392568796d043c794553e5bcaa797c906899e71f0Marius Renn  if (fbo_state_ == kStateComplete || texture_state_ == kStateUnmanaged) {
39430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return true;
39592568796d043c794553e5bcaa797c906899e71f0Marius Renn  } else if (fbo_state_ != kStateGenerated) {
39692568796d043c794553e5bcaa797c906899e71f0Marius Renn    LOGE("Attempting to attach texture to FBO with no FBO in place!");
39792568796d043c794553e5bcaa797c906899e71f0Marius Renn    return false;
39892568796d043c794553e5bcaa797c906899e71f0Marius Renn  }
39930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
40092568796d043c794553e5bcaa797c906899e71f0Marius Renn  // If texture has been generated, make sure it is allocated.
40192568796d043c794553e5bcaa797c906899e71f0Marius Renn  if (!AllocateTexture())
40230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
40330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
40430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Bind the frame buffer, and check if we it is already bound
40530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
40630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
40792568796d043c794553e5bcaa797c906899e71f0Marius Renn  // Bind the texture to the frame buffer
40892568796d043c794553e5bcaa797c906899e71f0Marius Renn  LOG_FRAME("Attaching tex %d w %d h %d to fbo %d", texture_id_, width_, height_, fbo_id_);
40992568796d043c794553e5bcaa797c906899e71f0Marius Renn  glFramebufferTexture2D(GL_FRAMEBUFFER,
41092568796d043c794553e5bcaa797c906899e71f0Marius Renn                         GL_COLOR_ATTACHMENT0,
41192568796d043c794553e5bcaa797c906899e71f0Marius Renn                         GL_TEXTURE_2D,
41292568796d043c794553e5bcaa797c906899e71f0Marius Renn                         texture_id_,
41392568796d043c794553e5bcaa797c906899e71f0Marius Renn                         0);
41430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
41530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Cleanup
41630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glBindTexture(GL_TEXTURE_2D, 0);
41730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glBindFramebuffer(GL_FRAMEBUFFER, 0);
41830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
41930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (GLEnv::CheckGLError("Texture Binding to FBO"))
42030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
42192568796d043c794553e5bcaa797c906899e71f0Marius Renn  else
42292568796d043c794553e5bcaa797c906899e71f0Marius Renn    fbo_state_ = kStateComplete;
42330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
42492568796d043c794553e5bcaa797c906899e71f0Marius Renn  return true;
42592568796d043c794553e5bcaa797c906899e71f0Marius Renn}
42692568796d043c794553e5bcaa797c906899e71f0Marius Renn
42792568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::ReattachTextureToFbo() {
42892568796d043c794553e5bcaa797c906899e71f0Marius Renn  return (fbo_state_ == kStateGenerated) ? AttachTextureToFbo() : true;
42992568796d043c794553e5bcaa797c906899e71f0Marius Renn}
43092568796d043c794553e5bcaa797c906899e71f0Marius Renn
43192568796d043c794553e5bcaa797c906899e71f0Marius Rennbool GLFrame::DetachTextureFromFbo() {
43292568796d043c794553e5bcaa797c906899e71f0Marius Renn  if (fbo_state_ == kStateComplete && texture_state_ == kStateComplete) {
43392568796d043c794553e5bcaa797c906899e71f0Marius Renn    LOG_FRAME("Detaching tex %d w %d h %d from fbo %d", texture_id_, width_, height_, fbo_id_);
43492568796d043c794553e5bcaa797c906899e71f0Marius Renn    glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_);
43592568796d043c794553e5bcaa797c906899e71f0Marius Renn    glFramebufferTexture2D(GL_FRAMEBUFFER,
43692568796d043c794553e5bcaa797c906899e71f0Marius Renn                           GL_COLOR_ATTACHMENT0,
43792568796d043c794553e5bcaa797c906899e71f0Marius Renn                           GL_TEXTURE_2D,
43892568796d043c794553e5bcaa797c906899e71f0Marius Renn                           0,
43992568796d043c794553e5bcaa797c906899e71f0Marius Renn                           0);
44092568796d043c794553e5bcaa797c906899e71f0Marius Renn    if (GLEnv::CheckGLError("Detaching texture to FBO"))
44192568796d043c794553e5bcaa797c906899e71f0Marius Renn      return false;
44292568796d043c794553e5bcaa797c906899e71f0Marius Renn    else
44392568796d043c794553e5bcaa797c906899e71f0Marius Renn      fbo_state_ = kStateGenerated;
44492568796d043c794553e5bcaa797c906899e71f0Marius Renn  }
44530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
44630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
44730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
448e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::UploadTexturePixels(const uint8_t* pixels) {
44930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Bind the texture object
45030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  FocusTexture();
45130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
45230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  // Load mipmap level 0
45330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_,
45430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni               0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
45530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
456f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  // Set the user specified texture parameters
457f5ae8eafa7605c6593f62f873b62cb64a3254db3Marius Renn  UpdateTexParameters();
45830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
45930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  if (GLEnv::CheckGLError("Texture Pixel Upload"))
46030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni    return false;
46130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
462776102d45a18a5df53d2ec76c5d93f20b3e99da1Marius Renn  texture_state_ = kStateComplete;
46330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni  return true;
46430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni}
46530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni
46630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} // namespace filterfw
46730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} // namespace android
468