gl_frame.cpp revision 511360e61650864ea22a171159efe073c80d0cdb
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), 51511360e61650864ea22a171159efe073c80d0cdbMarius Renn owns_(false) { 5230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 5330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 5430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::Init(int width, int height) { 5530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Make sure we haven't been initialized already 5630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (width_ == 0 && height_ == 0) { 5730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni InitDimensions(width, height); 5830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni owns_ = true; 5930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 6030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 6130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 6230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 6330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 6430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::InitWithTexture(GLint texture_id, int width, int height, bool owns, bool create_tex) { 6530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_id_ = texture_id; 6630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_state_ = create_tex ? kStateGenerated : kStateAllocated; 6730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni InitDimensions(width, height); 6830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni owns_ = owns; 6930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 7030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 7130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 7230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::InitWithFbo(GLint fbo_id, int width, int height, bool owns, bool create_fbo) { 7330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni fbo_id_ = fbo_id; 7430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni fbo_state_ = create_fbo ? kStateGenerated : kStateBound; 7530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni InitDimensions(width, height); 7630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni owns_ = owns; 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; 8430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni owns_ = true; 8530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return CreateTexture(); 8630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 8730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 8830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronivoid GLFrame::InitDimensions(int width, int height) { 8930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni width_ = width; 9030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni height_ = height; 9130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_width_ = width; 9230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_height_ = height; 9330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 9430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 9530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLFrame::~GLFrame() { 9630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni LOGV("Deleting texture %d and fbo %d", texture_id_, fbo_id_); 9730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (owns_) { 9830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glDeleteTextures(1, &texture_id_); 9930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glDeleteFramebuffers(1, &fbo_id_); 10030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 10130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 10230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 10330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::GenerateMipMap() { 104fb7c020acdd0fb38c9d2b6750d904b64cc78458dWei Hua if (FocusTexture()) { 10530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glGenerateMipmap(GL_TEXTURE_2D); 10630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri(GL_TEXTURE_2D, 10730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_TEXTURE_MIN_FILTER, 10830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_LINEAR_MIPMAP_NEAREST); 10930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return !GLEnv::CheckGLError("Generating MipMap!"); 11030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 11130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 11230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 11330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 11430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::SetTextureParameter(GLenum pname, GLint value) { 115fb7c020acdd0fb38c9d2b6750d904b64cc78458dWei Hua if (FocusTexture()) { 11630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri(GL_TEXTURE_2D, pname, value); 11730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return !GLEnv::CheckGLError("Setting texture parameter!"); 11830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 11930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 12030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 12130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 122e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::CopyDataTo(uint8_t* buffer, int size) { 12330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return (size >= Size()) 12430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni ? CopyPixelsTo(buffer) 12530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni : false; 12630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 12730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 128e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::CopyPixelsTo(uint8_t* buffer) { 12930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (texture_state_ == kStateAllocated) 13030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return ReadTexturePixels(buffer); 13130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni else if (fbo_state_ == kStateBound) 13230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return ReadFboPixels(buffer); 13330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni else 13430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 13530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 13630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 137e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::WriteData(const uint8_t* data, int data_size) { 13830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return (data_size == Size()) ? UploadTexturePixels(data) : false; 13930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 14030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 14130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::SetViewport(int x, int y, int width, int height) { 14230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_x_ = x; 14330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_y_ = y; 14430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_width_ = width; 14530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni vp_height_ = height; 14630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 14730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 14830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 14930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLFrame* GLFrame::Clone() const { 150511360e61650864ea22a171159efe073c80d0cdbMarius Renn GLFrame* target = new GLFrame(gl_env_); 15130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni target->Init(width_, height_); 15230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni target->CopyPixelsFrom(this); 15330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return target; 15430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 15530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 15630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::CopyPixelsFrom(const GLFrame* frame) { 15730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (frame == this) { 15830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 15930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } else if (frame && frame->width_ == width_ && frame->height_ == height_) { 160e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala std::vector<const GLFrame*> sources; 16130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni sources.push_back(frame); 16230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GetIdentity()->Process(sources, this); 16330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 16430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 16530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 16630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 16730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 16830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroniint GLFrame::Size() const { 16930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return width_ * height_ * 4; 17030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 17130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 17230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniShaderProgram* GLFrame::GetIdentity() const { 173511360e61650864ea22a171159efe073c80d0cdbMarius Renn ShaderProgram* stored_shader = gl_env_->ShaderWithKey(kIdentityShaderKey); 174511360e61650864ea22a171159efe073c80d0cdbMarius Renn if (!stored_shader) { 175511360e61650864ea22a171159efe073c80d0cdbMarius Renn stored_shader = ShaderProgram::CreateIdentity(gl_env_); 176511360e61650864ea22a171159efe073c80d0cdbMarius Renn gl_env_->AttachShader(kIdentityShaderKey, stored_shader); 177511360e61650864ea22a171159efe073c80d0cdbMarius Renn } 178511360e61650864ea22a171159efe073c80d0cdbMarius Renn return stored_shader; 17930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 18030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 18130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::BindFrameBuffer() const { 18230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind the FBO 18330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_); 18430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("FBO Binding")) return false; 18530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 18630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Set viewport 18730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glViewport(vp_x_, vp_y_, vp_width_, vp_height_); 18830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("ViewPort Setup")) return false; 18930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 19030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 19130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 19230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 19330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::FocusFrameBuffer() { 19430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create texture backing if necessary 19530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (texture_state_ == kStateUninitialized) { 19630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (!CreateTexture()) 19730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 19830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 19930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 20030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create and bind FBO to texture if necessary 20130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (fbo_state_ != kStateBound) { 20230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (!CreateFBO() || !BindTextureToFBO()) 20330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 20430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 20530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 20630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // And bind it. 20730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return BindFrameBuffer(); 20830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 20930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 21030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::BindTexture() const { 21130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindTexture(GL_TEXTURE_2D, texture_id_); 21230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return !GLEnv::CheckGLError("Texture Binding"); 21330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 21430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 21530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLuint GLFrame::GetTextureId() const { 21630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return texture_id_; 21730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 21830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 21930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// Returns the held FBO id. Only call this if the GLFrame holds an FBO. You 22030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni// can check this by calling HoldsFbo(). 22130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo CarceroniGLuint GLFrame::GetFboId() const { 22230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return fbo_id_; 22330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 22430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 22530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::FocusTexture() { 22630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Make sure we have a texture 22730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (!CreateTexture()) 22830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 22930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 23030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind the texture 23130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (!BindTexture()) 23230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 23330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 23430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return !GLEnv::CheckGLError("Texture Binding"); 23530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 23630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 23730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::CreateTexture() { 23830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (texture_state_ == kStateUninitialized) { 23930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Make sure texture not in use already 24030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (glIsTexture(texture_id_)) { 24130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni LOGE("GLFrame: Cannot generate texture id %d, as it is in use already!", texture_id_); 24230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 24330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 24430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 24530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Generate the texture 24630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glGenTextures (1, &texture_id_); 24730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("Texture Generation")) 24830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 24930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_state_ = kStateGenerated; 25030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 25130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 25230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 25330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 25430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 25530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::CreateFBO() { 25630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (fbo_state_ == kStateUninitialized) { 25730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Make sure FBO not in use already 25830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (glIsFramebuffer(fbo_id_)) { 25930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni LOGE("GLFrame: Cannot generate FBO id %d, as it is in use already!", fbo_id_); 26030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 26130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 26230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 26330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create FBO 26430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glGenFramebuffers(1, &fbo_id_); 26530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("FBO Generation")) 26630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 26730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni fbo_state_ = kStateGenerated; 26830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 26930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 27030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 27130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 27230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 273e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::ReadFboPixels(uint8_t* pixels) const { 27430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (fbo_state_ == kStateBound) { 27530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni BindFrameBuffer(); 27630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glReadPixels(0, 27730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 0, 27830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni width_, 27930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni height_, 28030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_RGBA, 28130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_UNSIGNED_BYTE, 28230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni pixels); 28330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return !GLEnv::CheckGLError("FBO Pixel Readout"); 28430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 28530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 28630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 28730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 288e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::ReadTexturePixels(uint8_t* pixels) const { 28930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Read pixels from texture if we do not have an FBO 29030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // NOTE: OpenGL ES does NOT support glGetTexImage() for reading out texture 29130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // data. The only way for us to get texture data is to create a new FBO and 29230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // render the current texture frame into it. As this is quite inefficient, 29330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // and unnecessary (this can only happen if the user is reading out data 29430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // that was just set, and not run through a filter), we warn the user about 29530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // this here. 29630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni LOGW("Warning: Reading pixel data from unfiltered GL frame. This is highly " 29730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni "inefficient. Please consider using your original pixel buffer " 29830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni "instead!"); 29930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 30030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create source frame set (unfortunately this requires an ugly const-cast, 30130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // as we need to wrap ourselves in a frame-set. Still, as this set is used 30230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // as input only, we are certain we will not be modified). 303e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvala std::vector<const GLFrame*> sources; 30430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni sources.push_back(this); 30530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 30630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Create target frame 307511360e61650864ea22a171159efe073c80d0cdbMarius Renn GLFrame target(gl_env_); 30830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni target.Init(width_, height_); 30930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 31030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Render the texture to the target 31130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GetIdentity()->Process(sources, &target); 31230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 31330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Get the pixel data 31430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return target.ReadFboPixels(pixels); 31530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 31630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 31730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceronibool GLFrame::BindTextureToFBO() { 31830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Check if we are already bound 31930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (texture_state_ == kStateBound && fbo_state_ == kStateBound) 32030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 32130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 32230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Otherwise check if the texture and fbo states are acceptable 32330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (texture_state_ != kStateGenerated 32430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni && texture_state_ != kStateAllocated 32530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni && fbo_state_ != kStateGenerated) 32630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 32730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 32830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind the frame buffer, and check if we it is already bound 32930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindFramebuffer(GL_FRAMEBUFFER, fbo_id_); 33030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 33130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind texture 33230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindTexture(GL_TEXTURE_2D, texture_id_); 33330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 33430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Set the texture format 33530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexImage2D(GL_TEXTURE_2D, 33630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 0, 33730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_RGBA, 33830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni width_, 33930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni height_, 34030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 0, 34130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_RGBA, 34230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_UNSIGNED_BYTE, 34330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni NULL); 34430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 34530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 34630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 34730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind the texture to the frame buffer 34830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni LOG_FRAME("Binding tex %d w %d h %d to fbo %d", texture_id_, width_, height_, fbo_id_); 34930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glFramebufferTexture2D(GL_FRAMEBUFFER, 35030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_COLOR_ATTACHMENT0, 35130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni GL_TEXTURE_2D, 35230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_id_, 35330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 0); 35430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni } 35530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 35630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Cleanup 35730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindTexture(GL_TEXTURE_2D, 0); 35830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glBindFramebuffer(GL_FRAMEBUFFER, 0); 35930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 36030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("Texture Binding to FBO")) 36130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 36230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 36330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_state_ = fbo_state_ = kStateBound; 36430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 36530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 36630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 367e9912de34684f1b8deaf36bcf77686152d33765dEino-Ville Talvalabool GLFrame::UploadTexturePixels(const uint8_t* pixels) { 36830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Bind the texture object 36930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni FocusTexture(); 37030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 37130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Load mipmap level 0 37230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 37330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 37430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 37530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni // Set the filtering mode 37630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 37730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 37830ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 37930ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni if (GLEnv::CheckGLError("Texture Pixel Upload")) 38030ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return false; 38130ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 38230ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni texture_state_ = kStateAllocated; 38330ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni return true; 38430ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} 38530ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni 38630ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} // namespace filterfw 38730ab3fc173709a491c9e2e103f53fb7c0d1b96b7Rodrigo Carceroni} // namespace android 388