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/geometry.h"
2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_buffer_interface.h"
2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_env.h"
2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/gl_frame.h"
2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/shader_program.h"
2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include "core/vertex_frame.h"
2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <string>
2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <sstream>
2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn#include <vector>
2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace android {
3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennnamespace filterfw {
3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// VBO attachment keys
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic const int kDefaultVboKey = 1;
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic const char* s_default_vertex_shader_source_ =
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "attribute vec4 a_position;\n"
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "attribute vec2 a_texcoord;\n"
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "varying vec2 v_texcoord;\n"
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "void main() {\n"
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "  gl_Position = a_position;\n"
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "  v_texcoord = a_texcoord;\n"
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "}\n";
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Helper Functions ////////////////////////////////////////////////////////////
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Maps coordinates x,y in the unit rectangle over to the quadrangle specified
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// by the four points in b. The result coordinates are written to xt and yt.
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic void GetTileCoords(const float* b, float x, float y, float* xt, float* yt) {
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w0 =  (1.0f - x) * (1.0f - y);
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w1 =  x * (1.0f - y);
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w2 =  (1.0f - x) * y;
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w3 =  x * y;
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  *xt = w0 * b[0] + w1 * b[2] + w2 * b[4] + w3 * b[6];
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  *yt = w0 * b[1] + w1 * b[3] + w2 * b[5] + w3 * b[7];
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic inline float AdjustRatio(float current, float next) {
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return (current + next) / 2.0;
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// VertexAttrib implementation /////////////////////////////////////////////////
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::VertexAttrib::VertexAttrib()
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : is_const(true),
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    index(-1),
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    normalized(false),
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    stride(0),
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    components(0),
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    offset(0),
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    type(GL_FLOAT),
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vbo(0),
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    values(NULL),
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owned_data(NULL) {
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// ShaderProgram implementation ////////////////////////////////////////////////
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::ShaderProgram(GLEnv* gl_env, const std::string& fragment_shader)
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : fragment_shader_source_(fragment_shader),
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_source_(s_default_vertex_shader_source_),
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fragment_shader_(0),
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_(0),
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    program_(0),
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    gl_env_(gl_env),
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    base_texture_unit_(GL_TEXTURE0),
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_(NULL),
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_(NULL),
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_(false),
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_x_count_(1),
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_y_count_(1),
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_count_(4),
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    draw_mode_(GL_TRIANGLE_STRIP),
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    clears_(false),
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    blending_(false),
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    sfactor_(GL_SRC_ALPHA),
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetDefaultCoords();
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::ShaderProgram(GLEnv* gl_env,
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             const std::string& vertex_shader,
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             const std::string& fragment_shader)
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : fragment_shader_source_(fragment_shader),
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_source_(vertex_shader),
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fragment_shader_(0),
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_(0),
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    program_(0),
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    gl_env_(gl_env),
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    base_texture_unit_(GL_TEXTURE0),
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_(NULL),
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_(NULL),
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_(false),
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_x_count_(1),
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_y_count_(1),
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_count_(4),
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    draw_mode_(GL_TRIANGLE_STRIP),
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    clears_(false),
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    blending_(false),
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    sfactor_(GL_SRC_ALPHA),
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetDefaultCoords();
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::~ShaderProgram() {
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete our vertex data
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  delete[] source_coords_;
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  delete[] target_coords_;
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete any owned attribute data
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  VertexAttribMap::const_iterator iter;
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (iter = attrib_values_.begin(); iter != attrib_values_.end(); ++iter) {
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const VertexAttrib& attrib = iter->second;
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (attrib.owned_data)
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      delete[] attrib.owned_data;
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetDefaultCoords() {
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!source_coords_)
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_ = new float[8];
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!target_coords_)
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_ = new float[8];
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[0] = 0.0f;
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[1] = 0.0f;
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[2] = 1.0f;
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[3] = 0.0f;
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[4] = 0.0f;
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[5] = 1.0f;
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[6] = 1.0f;
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[7] = 1.0f;
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[0] = -1.0f;
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[1] = -1.0f;
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[2] =  1.0f;
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[3] = -1.0f;
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[4] = -1.0f;
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[5] =  1.0f;
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[6] =  1.0f;
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[7] =  1.0f;
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram* ShaderProgram::CreateIdentity(GLEnv* gl_env) {
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const char* s_id_fragment_shader =
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "precision mediump float;\n"
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "uniform sampler2D tex_sampler_0;\n"
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "varying vec2 v_texcoord;\n"
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "void main() {\n"
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n"
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "}\n";
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ShaderProgram* result = new ShaderProgram(gl_env, s_id_fragment_shader);
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  result->CompileAndLink();
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::IsVarValid(ProgramVar var) {
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return var != -1;
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Process(const std::vector<const GLTextureHandle*>& input,
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                            GLFrameBufferHandle* output) {
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // TODO: This can be optimized: If the input and output are the same, as in
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // the last iteration (typical of a multi-pass filter), a lot of this setup
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // may be skipped.
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Abort if program did not successfully compile and link
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsExecutable()) {
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: unexecutable program!");
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Focus the FBO of the output
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!output->FocusFrameBuffer()) {
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Unable to focus frame buffer");
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Get all required textures
19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLuint> textures;
20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLenum> targets;
20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (unsigned i = 0; i < input.size(); ++i) {
20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Get the current input frame and make sure it is a GL frame
20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (input[i]) {
20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Get the texture bound to that frame
20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const GLuint tex_id = input[i]->GetTextureId();
20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const GLenum target = input[i]->GetTextureTarget();
20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (tex_id == 0) {
20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        ALOGE("ShaderProgram: invalid texture id at input: %d!", i);
20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      textures.push_back(tex_id);
21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      targets.push_back(target);
21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // And render!
21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!RenderFrame(textures, targets)) {
21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Unable to render frame");
21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Process(const std::vector<const GLFrame*>& input, GLFrame* output) {
22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<const GLTextureHandle*> textures(input.size());
22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::copy(input.begin(), input.end(), textures.begin());
22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return Process(textures, output);
22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetSourceRect(float x, float y, float width, float height) {
23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Quad quad(Point(x,          y),
23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y),
23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x,          y + height),
23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y + height));
23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetSourceRegion(quad);
23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetSourceRegion(const Quad& quad) {
23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int index = 0;
24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < 4; ++i, index += 2) {
24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_[index]   = quad.point(i).x();
24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_[index+1] = quad.point(i).y();
24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTargetRect(float x, float y, float width, float height) {
24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Quad quad(Point(x,          y),
24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y),
24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x,          y + height),
25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y + height));
25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetTargetRegion(quad);
25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTargetRegion(const Quad& quad) {
25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int index = 0;
25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < 4; ++i, index += 2) {
25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_[index]   = (quad.point(i).x() * 2.0) - 1.0;
25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_[index+1] = (quad.point(i).y() * 2.0) - 1.0;
25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CompileAndLink() {
26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we haven't compiled and linked already
26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (vertex_shader_ != 0 || fragment_shader_ != 0 || program_ != 0) {
26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Attempting to re-compile shaders!");
26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Compile vertex shader
27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vertex_shader_ = CompileShader(GL_VERTEX_SHADER,
27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                 vertex_shader_source_.c_str());
27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!vertex_shader_) {
27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader compilation failed!");
27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Compile fragment shader
27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  fragment_shader_ = CompileShader(GL_FRAGMENT_SHADER,
27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                   fragment_shader_source_.c_str());
28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!fragment_shader_)
28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Link
28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint shaders[2] = { vertex_shader_, fragment_shader_ };
28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  program_ = LinkProgram(shaders, 2);
28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Scan for all uniforms in the program
28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ScanUniforms();
28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Check if we manage all coordinates
29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (program_ != 0) {
29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_ = (tex_coord_attr >= 0 && pos_coord_attr >= 0);
29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else {
29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Could not link shader program!");
29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint ShaderProgram::CompileShader(GLenum shader_type, const char* source) {
30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  LOG_FRAME("Compiling source:\n[%s]", source);
30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create shader
30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint shader = glCreateShader(shader_type);
30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (shader) {
30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Compile source
31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glShaderSource(shader, 1, &source, NULL);
31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glCompileShader(shader);
31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Check for compilation errors
31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint compiled = 0;
31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!compiled) {
31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Log the compilation error messages
31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("Problem compiling shader! Source:");
31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("%s", source);
32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      std::string src(source);
32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      unsigned int cur_pos = 0;
32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      unsigned int next_pos = 0;
32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      int line_number = 1;
32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      while ( (next_pos = src.find_first_of('\n', cur_pos)) != std::string::npos) {
32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        ALOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        cur_pos = next_pos + 1;
32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        line_number++;
32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GLint log_length = 0;
33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (log_length) {
33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        char* error_log = new char[log_length];
33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (error_log) {
33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetShaderInfoLog(shader, log_length, NULL, error_log);
33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          ALOGE("Shader compilation error %d:\n%s\n", shader_type, error_log);
33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          delete[] error_log;
33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glDeleteShader(shader);
34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      shader = 0;
34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return shader;
34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint ShaderProgram::LinkProgram(GLuint* shaders, GLuint count) {
34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint program = glCreateProgram();
35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (program) {
35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Attach all compiled shaders
35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    for (GLuint i = 0; i < count; ++i) {
35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glAttachShader(program, shaders[i]);
35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (GLEnv::CheckGLError("glAttachShader")) return 0;
35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Link
35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glLinkProgram(program);
35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Check for linking errors
36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint linked = 0;
36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetProgramiv(program, GL_LINK_STATUS, &linked);
36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (linked != GL_TRUE) {
36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Log the linker error messages
36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GLint log_length = 0;
36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (log_length) {
36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        char* error_log = new char[log_length];
36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (error_log) {
37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetProgramInfoLog(program, log_length, NULL, error_log);
37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          ALOGE("Program Linker Error:\n%s\n", error_log);
37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          delete[] error_log;
37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glDeleteProgram(program);
37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      program = 0;
37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return program;
38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::ScanUniforms() {
38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int uniform_count;
38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int buffer_size;
38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLenum type;
38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint capacity;
38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetProgramiv(program_, GL_ACTIVE_UNIFORMS, &uniform_count);
38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetProgramiv(program_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &buffer_size);
38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLchar> name(buffer_size);
39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < uniform_count; ++i) {
39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetActiveUniform(program_, i, buffer_size, NULL, &capacity, &type, &name[0]);
39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar uniform_id = glGetUniformLocation(program_, &name[0]);
39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    uniform_indices_[uniform_id] = i;
39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushCoords(ProgramVar attr, float* coords) {
39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // If the shader does not define these, we simply ignore the coordinates, and assume that the
39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // user is managing coordinates.
40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (attr >= 0) {
40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const uint8_t* data = reinterpret_cast<const uint8_t*>(coords);
40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindBuffer(GL_ARRAY_BUFFER, 0);
40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glVertexAttribPointer(attr, 2, GL_FLOAT, false, 2 * sizeof(float), data);
40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glEnableVertexAttribArray(attr);
40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Pushing vertex coordinates");
40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushSourceCoords(float* coords) {
41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return PushCoords(tex_coord_attr, coords);
41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushTargetCoords(float* coords) {
41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return PushCoords(pos_coord_attr, coords);
41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstd::string ShaderProgram::InputTextureUniformName(int index) {
42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::stringstream tex_name;
42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_name << "tex_sampler_" << index;
42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return tex_name.str();
42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::BindInputTextures(const std::vector<GLuint>& textures,
42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                      const std::vector<GLenum>& targets) {
42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (unsigned i = 0; i < textures.size(); ++i) {
42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Activate texture unit i
43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glActiveTexture(BaseTextureUnit() + i);
43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Activating Texture Unit"))
43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Bind our texture
43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindTexture(targets[i], textures[i]);
43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("Binding texture %d", textures[i]);
43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Binding Texture"))
43865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Set the texture handle in the shader to unit i
44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar tex_var = GetUniform(InputTextureUniformName(i));
44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (tex_var >= 0) {
44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glUniform1i(tex_var, i);
44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else {
44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("ShaderProgram: Shader does not seem to support %d number of "
44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn           "inputs! Missing uniform 'tex_sampler_%d'!", textures.size(), i);
44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Texture Variable Binding"))
45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::UseProgram() {
45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::GetCurrentProgram() != program_) {
45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("Using program %d", program_);
46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glUseProgram(program_);
46165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Use Program");
46265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
46365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
46465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
46565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::RenderFrame(const std::vector<GLuint>& textures,
46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                const std::vector<GLenum>& targets) {
46865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we have enough texture units to accomodate the textures
46965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (textures.size() > static_cast<unsigned>(MaxTextureUnits())) {
47065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: Number of input textures is unsupported on this "
47165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "platform!");
47265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
47365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
47465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
47565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Prepare to render
47665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!BeginDraw()) {
47765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: couldn't initialize gl for drawing!");
47865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
47965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
48065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
48165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind input textures
48265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!BindInputTextures(textures, targets)) {
48365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("BindInputTextures failed");
48465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
48565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
48665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
48765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (LOG_EVERY_FRAME) {
48865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    int fbo, program, buffer;
48965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
49065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
49165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
49265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGV("RenderFrame: fbo %d prog %d buff %d", fbo, program, buffer);
49365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
49465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
49565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Render!
49665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const bool requestTile = (tile_x_count_ != 1 || tile_y_count_ != 1);
49765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const bool success = (!requestTile || !manage_coordinates_  || vertex_count_ != 4)
49865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ? Draw()
49965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      : DrawTiled();
50065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Pop vertex attributes
50265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  PopAttributes();
50365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return success && !GLEnv::CheckGLError("Rendering");
50565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
50665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Draw() {
50865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (PushSourceCoords(source_coords_) && PushTargetCoords(target_coords_)) {
50965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glDrawArrays(draw_mode_, 0, vertex_count_);
51065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
51165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
51265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
51365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
51465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
51565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::DrawTiled() {
51665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Target coordinate step size
51765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  float s[8];
51865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  float t[8];
51965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
52065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Step sizes
52165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float xs = 1.0f / static_cast<float>(tile_x_count_);
52265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float ys = 1.0f / static_cast<float>(tile_y_count_);
52365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
52465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Tile drawing loop
52565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < tile_x_count_; ++i) {
52665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    for (int j = 0; j < tile_y_count_; ++j) {
52765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Current coordinates in unit rectangle
52865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const float x = i / static_cast<float>(tile_x_count_);
52965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const float y = j / static_cast<float>(tile_y_count_);
53065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
53165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Source coords
53265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x, y, &s[0], &s[1]);
53365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x + xs, y, &s[2], &s[3]);
53465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x, y + ys, &s[4], &s[5]);
53565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x + xs, y + ys, &s[6], &s[7]);
53665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
53765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Target coords
53865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x, y, &t[0], &t[1]);
53965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x + xs, y, &t[2], &t[3]);
54065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x, y + ys, &t[4], &t[5]);
54165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x + xs, y + ys, &t[6], &t[7]);
54265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
54365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (PushSourceCoords(s) && PushTargetCoords(t)) {
54465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glDrawArrays(draw_mode_, 0, vertex_count_);
54565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Yield();
54665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      } else {
54765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
54865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
54965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
55065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
55165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
55265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
55365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::Yield() {
55565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glFinish();
55665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
55765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::BeginDraw() {
55965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Activate shader program
56065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!UseProgram())
56165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
56265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
56365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Push vertex attributes
56465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  PushAttributes();
56565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
56665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Clear output, if requested
56765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (clears_) {
56865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glClearColor(clear_color_.red,
56965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.green,
57065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.blue,
57165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.alpha);
57265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glClear(GL_COLOR_BUFFER_BIT);
57365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
57465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
57565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Enable/Disable blending
57665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (blending_) {
57765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glEnable(GL_BLEND);
57865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBlendFunc(sfactor_, dfactor_);
57965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else glDisable(GL_BLEND);
58065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
58165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
58265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
58365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
58465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxVaryingCount() {
58565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint result;
58665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
58765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
58865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
58965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxTextureUnits() {
59165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
59265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
59365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetDrawMode(GLenum mode) {
59565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  draw_mode_ = mode;
59665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
59765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetClearsOutput(bool clears) {
59965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clears_ = clears;
60065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
60165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
60265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetClearColor(float red, float green, float blue, float alpha) {
60365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.red = red;
60465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.green = green;
60565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.blue = blue;
60665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.alpha = alpha;
60765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
60865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
60965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTileCounts(int x_count, int y_count) {
61065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tile_x_count_ = x_count;
61165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tile_y_count_ = y_count;
61265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
61365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
61465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Variable Value Setting Helpers //////////////////////////////////////////////
61565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckValueCount(const std::string& var_type,
61665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    const std::string& var_name,
61765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int expected_count,
61865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int components,
61965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int value_size) {
62065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (expected_count != (value_size / components)) {
62165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader Program: %s Value Error (%s): Expected value length %d "
62265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "(%d components), but received length of %d (%d components)!",
62365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         var_type.c_str(), var_name.c_str(),
62465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         expected_count, components * expected_count,
62565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         value_size / components, value_size);
62665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
62765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
62865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
62965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
63065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
63165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckValueMult(const std::string& var_type,
63265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                   const std::string& var_name,
63365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                   int components,
63465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                   int value_size) {
63565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (value_size % components != 0) {
63665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader Program: %s Value Error (%s): Value must be multiple of %d, "
63765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "but %d elements were passed!", var_type.c_str(), var_name.c_str(),
63865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         components, value_size);
63965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
64065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
64165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
64265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
64365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
64465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckVarValid(ProgramVar var) {
64565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsVarValid(var)) {
64665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader Program: Attempting to access invalid variable!");
64765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
64865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
64965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
65065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
65165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
65265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Uniforms ////////////////////////////////////////////////////////////////////
65365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckUniformValid(ProgramVar var) {
65465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsVarValid(var) || uniform_indices_.find(var) == uniform_indices_.end()) {
65565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader Program: Attempting to access unknown uniform %d!", var);
65665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
65765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
65865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
65965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
66065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
66165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxUniformCount() {
66265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Here we return the minimum of the max uniform count for fragment and vertex
66365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // shaders.
66465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint count1, count2;
66565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &count1);
66665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &count2);
66765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return count1 < count2 ? count1 : count2;
66865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
66965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
67065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennProgramVar ShaderProgram::GetUniform(const std::string& name) const {
67165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsExecutable()) {
67265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: Error: Must link program before querying uniforms!");
67365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return -1;
67465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
67565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return glGetUniformLocation(program_, name.c_str());
67665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
67765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
67865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var, int value) {
67965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckVarValid(var))
68065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
68165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
68265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Uniforms are local to the currently used program.
68365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (UseProgram()) {
68465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glUniform1i(var, value);
68565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Set Uniform Value (int)");
68665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
68765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
68865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
68965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
69065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var, float value) {
69165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckVarValid(var))
69265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
69365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
69465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Uniforms are local to the currently used program.
69565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (UseProgram()) {
69665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glUniform1f(var, value);
69765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Set Uniform Value (float)");
69865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
69965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
70065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
70165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
70265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var,
70365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    const int* values,
70465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int count) {
70565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckUniformValid(var))
70665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
70765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
70865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we have values at all
70965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (count == 0)
71065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
71165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
71265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Uniforms are local to the currently used program.
71365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (UseProgram()) {
71465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Get uniform information
71565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint capacity;
71665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLenum type;
71765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    char name[128];
71865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetActiveUniform(program_, IndexOfUniform(var), 128, NULL, &capacity, &type, name);
71965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
72065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Make sure passed values are compatible
72165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const int components = GLEnv::NumberOfComponents(type);
72265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!CheckValueCount("Uniform (int)", name, capacity, components, count)
72365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ||  !CheckValueMult ("Uniform (int)", name, components, count))
72465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
72565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
72665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Set value based on type
72765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const int n = count / components;
72865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    switch(type) {
72965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_INT:
73065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform1iv(var, n, values);
73165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
73265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
73365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_INT_VEC2:
73465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform2iv(var, n, values);
73565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
73665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
73765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_INT_VEC3:
73865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform3iv(var, n, values);
73965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
74065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
74165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_INT_VEC4:
74265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform4iv(var, n, values);
74365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
74465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
74565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      default:
74665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
74765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    };
74865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Set Uniform Value");
74965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
75065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
75165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
75265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
75365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var,
75465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    const float* values,
75565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int count) {
75665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckUniformValid(var))
75765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
75865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
75965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we have values at all
76065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (count == 0)
76165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
76265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
76365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Uniforms are local to the currently used program.
76465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (UseProgram()) {
76565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Get uniform information
76665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint capacity;
76765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLenum type;
76865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    char name[128];
76965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetActiveUniform(program_, IndexOfUniform(var), 128, NULL, &capacity, &type, name);
77065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
77165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Make sure passed values are compatible
77265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const int components = GLEnv::NumberOfComponents(type);
77365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!CheckValueCount("Uniform (float)", name, capacity, components, count)
77465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ||  !CheckValueMult ("Uniform (float)", name, components, count))
77565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
77665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
77765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Set value based on type
77865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const int n = count / components;
77965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    switch(type) {
78065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT:
78165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform1fv(var, n, values);
78265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
78365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
78465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_VEC2:
78565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform2fv(var, n, values);
78665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
78765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
78865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_VEC3:
78965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform3fv(var, n, values);
79065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
79165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
79265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_VEC4:
79365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniform4fv(var, n, values);
79465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
79565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
79665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_MAT2:
79765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniformMatrix2fv(var, n, GL_FALSE, values);
79865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
79965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
80065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_MAT3:
80165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniformMatrix3fv(var, n, GL_FALSE, values);
80265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
80365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
80465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      case GL_FLOAT_MAT4:
80565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glUniformMatrix4fv(var, n, GL_FALSE, values);
80665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        break;
80765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
80865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      default:
80965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
81065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    };
81165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Set Uniform Value");
81265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
81365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
81465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
81565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
81665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) {
81765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return SetUniformValue(var, &values[0], values.size());
81865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
81965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
82065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(ProgramVar var,
82165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    const std::vector<float>& values) {
82265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return SetUniformValue(var, &values[0], values.size());
82365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
82465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
82565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetUniformValue(const std::string& name, const Value& value) {
82665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (ValueIsFloat(value))
82765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return SetUniformValue(GetUniform(name), GetFloatValue(value));
82865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else if (ValueIsInt(value))
82965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return SetUniformValue(GetUniform(name), GetIntValue(value));
83065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else if (ValueIsFloatArray(value))
83165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return SetUniformValue(GetUniform(name), GetFloatArrayValue(value), GetValueCount(value));
83265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else if (ValueIsIntArray(value))
83365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return SetUniformValue(GetUniform(name), GetIntArrayValue(value), GetValueCount(value));
83465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  else
83565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
83665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
83765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
83865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennValue ShaderProgram::GetUniformValue(const std::string& name) {
83965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ProgramVar var = GetUniform(name);
84065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (CheckUniformValid(var)) {
84165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Get uniform information
84265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint capacity;
84365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLenum type;
84465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetActiveUniform(program_, IndexOfUniform(var), 0, NULL, &capacity, &type, NULL);
84565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!GLEnv::CheckGLError("Get Active Uniform")) {
84665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Get value based on type, and wrap in value object
84765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      switch(type) {
84865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_INT: {
84965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          int value;
85065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformiv(program_, var, &value);
85165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntValue(value)
85265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
85365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
85465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
85565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_INT_VEC2: {
85665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          int value[2];
85765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformiv(program_, var, &value[0]);
85865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 2)
85965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
86065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
86165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
86265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_INT_VEC3: {
86365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          int value[3];
86465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformiv(program_, var, &value[0]);
86565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 3)
86665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
86765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
86865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
86965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_INT_VEC4: {
87065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          int value[4];
87165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformiv(program_, var, &value[0]);
87265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 4)
87365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
87465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
87565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
87665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT: {
87765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value;
87865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value);
87965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatValue(value)
88065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
88165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
88265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
88365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_VEC2: {
88465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[2];
88565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
88665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 2)
88765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
88865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
88965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
89065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_VEC3: {
89165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[3];
89265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
89365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 3)
89465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
89565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
89665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
89765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_VEC4: {
89865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[4];
89965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
90065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 4)
90165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
90265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
90365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
90465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_MAT2: {
90565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[4];
90665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
90765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 4)
90865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
90965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
91065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
91165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_MAT3: {
91265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[9];
91365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
91465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 9)
91565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
91665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
91765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
91865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case GL_FLOAT_MAT4: {
91965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          float value[16];
92065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetUniformfv(program_, var, &value[0]);
92165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 16)
92265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                                          : MakeNullValue();
92365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        } break;
92465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
92565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
92665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
92765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return MakeNullValue();
92865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
92965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
93065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint ShaderProgram::IndexOfUniform(ProgramVar var) {
93165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return uniform_indices_[var];
93265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
93365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
93465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Attributes //////////////////////////////////////////////////////////////////////////////////////
93565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxAttributeCount() {
93665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint result;
93765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result);
93865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
93965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
94065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
94165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennProgramVar ShaderProgram::GetAttribute(const std::string& name) const {
94265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsExecutable()) {
94365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: Error: Must link program before querying attributes!");
94465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return -1;
94565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else if (name == PositionAttributeName() || name == TexCoordAttributeName()) {
94665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGW("ShaderProgram: Attempting to overwrite internal vertex attribute '%s'!", name.c_str());
94765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
94865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return glGetAttribLocation(program_, name.c_str());
94965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
95065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
95165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetAttributeValues(ProgramVar var,
95265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       const VertexFrame* vbo,
95365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       GLenum type,
95465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int components,
95565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int stride,
95665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int offset,
95765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       bool normalize) {
95865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckVarValid(var))
95965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
96065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
96165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (vbo) {
96265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    VertexAttrib attrib;
96365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.is_const = false;
96465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.index = var;
96565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.components = components;
96665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.normalized = normalize;
96765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.stride = stride;
96865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.type = type;
96965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.vbo = vbo->GetVboId();
97065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.offset = offset;
97165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
97265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return StoreAttribute(attrib);
97365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
97465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
97565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
97665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
97765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetAttributeValues(ProgramVar var,
97865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       const uint8_t* data,
97965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       GLenum type,
98065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int components,
98165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int stride,
98265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int offset,
98365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       bool normalize) {
98465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckVarValid(var))
98565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
98665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
98765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (data) {
98865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    VertexAttrib attrib;
98965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.is_const = false;
99065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.index = var;
99165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.components = components;
99265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.normalized = normalize;
99365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.stride = stride;
99465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.type = type;
99565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib.values = data + offset;
99665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
99765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return StoreAttribute(attrib);
99865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
99965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
100065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
100165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
100265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetAttributeValues(ProgramVar var,
100365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       const std::vector<float>& data,
100465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int components) {
100565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return SetAttributeValues(var, &data[0], data.size(), components);
100665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
100765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
100865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::SetAttributeValues(ProgramVar var,
100965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       const float* data,
101065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int total,
101165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                       int components) {
101265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!CheckVarValid(var))
101365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
101465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
101565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure the passed data vector has a valid size
101665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (total  % components != 0) {
101765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: Invalid attribute vector given! Specified a component "
101865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "count of %d, but passed a non-multiple vector of size %d!",
101965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         components, total);
102065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
102165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
102265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
102365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Copy the data to a buffer we own
102465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  float* data_cpy = new float[total];
102565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  memcpy(data_cpy, data, sizeof(float) * total);
102665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
102765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Store the attribute
102865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  VertexAttrib attrib;
102965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.is_const = false;
103065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.index = var;
103165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.components = components;
103265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.normalized = false;
103365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.stride = components * sizeof(float);
103465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.type = GL_FLOAT;
103565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.values = data_cpy;
103665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  attrib.owned_data = data_cpy; // Marks this for deletion later on
103765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
103865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return StoreAttribute(attrib);
103965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
104065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
104165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
104265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (attrib.index >= 0) {
104365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    attrib_values_[attrib.index] = attrib;
104465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
104565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
104665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
104765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
104865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
104965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushAttributes() {
105065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
105165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn       iter != attrib_values_.end();
105265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn       ++iter) {
105365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const VertexAttrib& attrib = iter->second;
105465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
105565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (attrib.is_const) {
105665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Set constant attribute values (must be specified as host values)
105765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (!attrib.values)
105865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
105965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
106065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const float* values = reinterpret_cast<const float*>(attrib.values);
106165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      switch (attrib.components) {
106265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case 1: glVertexAttrib1fv(attrib.index, values); break;
106365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case 2: glVertexAttrib2fv(attrib.index, values); break;
106465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case 3: glVertexAttrib3fv(attrib.index, values); break;
106565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        case 4: glVertexAttrib4fv(attrib.index, values); break;
106665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        default: return false;
106765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
106865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glDisableVertexAttribArray(attrib.index);
106965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else {
107065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Set per-vertex values
107165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (attrib.values) {
107265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Make sure no buffer is bound and set attribute
107365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glBindBuffer(GL_ARRAY_BUFFER, 0);
107465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
107565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glVertexAttribPointer(attrib.index,
107665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.components,
107765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.type,
107865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.normalized,
107965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.stride,
108065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.values);
108165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      } else if (attrib.vbo) {
108265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        // Bind VBO and set attribute
108365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glBindBuffer(GL_ARRAY_BUFFER, attrib.vbo);
108465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
108565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glVertexAttribPointer(attrib.index,
108665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.components,
108765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.type,
108865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.normalized,
108965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              attrib.stride,
109065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                              reinterpret_cast<const void*>(attrib.offset));
109165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      } else {
109265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
109365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
109465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glEnableVertexAttribArray(attrib.index);
109565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
109665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
109765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Make sure everything worked
109865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Pushing Vertex Attributes"))
109965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
110065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
110165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
110265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
110365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
110465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
110565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PopAttributes() {
110665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Disable vertex attributes
110765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
110865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn       iter != attrib_values_.end();
110965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn       ++iter) {
111065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glDisableVertexAttribArray(iter->second.index);
111165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
111265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Unbind buffer: Very important as this greatly affects what glVertexAttribPointer does!
111365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glBindBuffer(GL_ARRAY_BUFFER, 0);
111465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return !GLEnv::CheckGLError("Popping Vertex Attributes");
111565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
111665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
111765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetVertexCount(int count) {
111865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vertex_count_ = count;
111965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
112065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
112165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace filterfw
112265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} // namespace android
1123