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 Rennstatic const char* s_default_vertex_shader_source_ =
3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "attribute vec4 a_position;\n"
3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "attribute vec2 a_texcoord;\n"
3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "varying vec2 v_texcoord;\n"
3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "void main() {\n"
3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "  gl_Position = a_position;\n"
3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "  v_texcoord = a_texcoord;\n"
4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  "}\n";
4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Helper Functions ////////////////////////////////////////////////////////////
4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Maps coordinates x,y in the unit rectangle over to the quadrangle specified
4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// by the four points in b. The result coordinates are written to xt and yt.
4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstatic void GetTileCoords(const float* b, float x, float y, float* xt, float* yt) {
4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w0 =  (1.0f - x) * (1.0f - y);
4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w1 =  x * (1.0f - y);
4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w2 =  (1.0f - x) * y;
4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float w3 =  x * y;
5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  *xt = w0 * b[0] + w1 * b[2] + w2 * b[4] + w3 * b[6];
5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  *yt = w0 * b[1] + w1 * b[3] + w2 * b[5] + w3 * b[7];
5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// VertexAttrib implementation /////////////////////////////////////////////////
5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::VertexAttrib::VertexAttrib()
5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : is_const(true),
5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    index(-1),
5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    normalized(false),
6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    stride(0),
6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    components(0),
6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    offset(0),
6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    type(GL_FLOAT),
6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vbo(0),
6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    values(NULL),
6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    owned_data(NULL) {
6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// ShaderProgram implementation ////////////////////////////////////////////////
7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::ShaderProgram(GLEnv* gl_env, const std::string& fragment_shader)
7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : fragment_shader_source_(fragment_shader),
7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_source_(s_default_vertex_shader_source_),
7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fragment_shader_(0),
7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_(0),
7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    program_(0),
7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    gl_env_(gl_env),
7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    base_texture_unit_(GL_TEXTURE0),
7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_(NULL),
7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_(NULL),
8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_(false),
8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_x_count_(1),
8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_y_count_(1),
8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_count_(4),
8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    draw_mode_(GL_TRIANGLE_STRIP),
8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    clears_(false),
8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    blending_(false),
8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    sfactor_(GL_SRC_ALPHA),
8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetDefaultCoords();
9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::ShaderProgram(GLEnv* gl_env,
9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             const std::string& vertex_shader,
9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                             const std::string& fragment_shader)
9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  : fragment_shader_source_(fragment_shader),
9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_source_(vertex_shader),
9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    fragment_shader_(0),
9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_shader_(0),
9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    program_(0),
10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    gl_env_(gl_env),
10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    base_texture_unit_(GL_TEXTURE0),
10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_(NULL),
10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_(NULL),
10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_(false),
10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_x_count_(1),
10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    tile_y_count_(1),
10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    vertex_count_(4),
10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    draw_mode_(GL_TRIANGLE_STRIP),
10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    clears_(false),
11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    blending_(false),
11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    sfactor_(GL_SRC_ALPHA),
11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetDefaultCoords();
11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram::~ShaderProgram() {
11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete our vertex data
11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  delete[] source_coords_;
11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  delete[] target_coords_;
12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Delete any owned attribute data
12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  VertexAttribMap::const_iterator iter;
12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (iter = attrib_values_.begin(); iter != attrib_values_.end(); ++iter) {
12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const VertexAttrib& attrib = iter->second;
12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (attrib.owned_data)
12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      delete[] attrib.owned_data;
12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetDefaultCoords() {
13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!source_coords_)
13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_ = new float[8];
13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!target_coords_)
13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_ = new float[8];
13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[0] = 0.0f;
13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[1] = 0.0f;
13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[2] = 1.0f;
13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[3] = 0.0f;
14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[4] = 0.0f;
14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[5] = 1.0f;
14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[6] = 1.0f;
14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  source_coords_[7] = 1.0f;
14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[0] = -1.0f;
14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[1] = -1.0f;
14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[2] =  1.0f;
14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[3] = -1.0f;
14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[4] = -1.0f;
15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[5] =  1.0f;
15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[6] =  1.0f;
15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  target_coords_[7] =  1.0f;
15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennShaderProgram* ShaderProgram::CreateIdentity(GLEnv* gl_env) {
15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const char* s_id_fragment_shader =
15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "precision mediump float;\n"
15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "uniform sampler2D tex_sampler_0;\n"
16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "varying vec2 v_texcoord;\n"
16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "void main() {\n"
16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n"
16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    "}\n";
16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ShaderProgram* result = new ShaderProgram(gl_env, s_id_fragment_shader);
16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  result->CompileAndLink();
16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::IsVarValid(ProgramVar var) {
17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return var != -1;
17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Process(const std::vector<const GLTextureHandle*>& input,
17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                            GLFrameBufferHandle* output) {
17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // TODO: This can be optimized: If the input and output are the same, as in
17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // the last iteration (typical of a multi-pass filter), a lot of this setup
17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // may be skipped.
17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Abort if program did not successfully compile and link
18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!IsExecutable()) {
18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: unexecutable program!");
18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Focus the FBO of the output
18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!output->FocusFrameBuffer()) {
18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Unable to focus frame buffer");
18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Get all required textures
19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLuint> textures;
19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLenum> targets;
19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (unsigned i = 0; i < input.size(); ++i) {
19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Get the current input frame and make sure it is a GL frame
19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (input[i]) {
19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Get the texture bound to that frame
19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const GLuint tex_id = input[i]->GetTextureId();
19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const GLenum target = input[i]->GetTextureTarget();
20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (tex_id == 0) {
20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        ALOGE("ShaderProgram: invalid texture id at input: %d!", i);
20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      textures.push_back(tex_id);
20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      targets.push_back(target);
20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // And render!
21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!RenderFrame(textures, targets)) {
21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Unable to render frame");
21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Process(const std::vector<const GLFrame*>& input, GLFrame* output) {
21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<const GLTextureHandle*> textures(input.size());
21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::copy(input.begin(), input.end(), textures.begin());
22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return Process(textures, output);
22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetSourceRect(float x, float y, float width, float height) {
22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Quad quad(Point(x,          y),
22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y),
22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x,          y + height),
22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y + height));
22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetSourceRegion(quad);
22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetSourceRegion(const Quad& quad) {
23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int index = 0;
23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < 4; ++i, index += 2) {
23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_[index]   = quad.point(i).x();
23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    source_coords_[index+1] = quad.point(i).y();
23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTargetRect(float x, float y, float width, float height) {
24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  Quad quad(Point(x,          y),
24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y),
24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x,          y + height),
24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn            Point(x + width,  y + height));
24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  SetTargetRegion(quad);
24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTargetRegion(const Quad& quad) {
24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int index = 0;
24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < 4; ++i, index += 2) {
25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_[index]   = (quad.point(i).x() * 2.0) - 1.0;
25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    target_coords_[index+1] = (quad.point(i).y() * 2.0) - 1.0;
25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CompileAndLink() {
25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we haven't compiled and linked already
25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (vertex_shader_ != 0 || fragment_shader_ != 0 || program_ != 0) {
25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Attempting to re-compile shaders!");
25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Compile vertex shader
26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  vertex_shader_ = CompileShader(GL_VERTEX_SHADER,
26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                 vertex_shader_source_.c_str());
26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!vertex_shader_) {
26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader compilation failed!");
26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Compile fragment shader
27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  fragment_shader_ = CompileShader(GL_FRAGMENT_SHADER,
27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                   fragment_shader_source_.c_str());
27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!fragment_shader_)
27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Link
27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint shaders[2] = { vertex_shader_, fragment_shader_ };
27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  program_ = LinkProgram(shaders, 2);
27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Scan for all uniforms in the program
28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ScanUniforms();
28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Check if we manage all coordinates
28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (program_ != 0) {
28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    manage_coordinates_ = (tex_coord_attr >= 0 && pos_coord_attr >= 0);
28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else {
28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Could not link shader program!");
29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint ShaderProgram::CompileShader(GLenum shader_type, const char* source) {
29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  LOG_FRAME("Compiling source:\n[%s]", source);
29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Create shader
30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint shader = glCreateShader(shader_type);
30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (shader) {
30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Compile source
30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glShaderSource(shader, 1, &source, NULL);
30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glCompileShader(shader);
30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Check for compilation errors
30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint compiled = 0;
30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (!compiled) {
31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Log the compilation error messages
31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("Problem compiling shader! Source:");
31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ALOGE("%s", source);
31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      std::string src(source);
314e5160e7e59f96aa457e7a4217197150086e8b7caAndreas Gampe      size_t cur_pos = 0;
315e5160e7e59f96aa457e7a4217197150086e8b7caAndreas Gampe      size_t next_pos = 0;
316e5160e7e59f96aa457e7a4217197150086e8b7caAndreas Gampe      size_t line_number = 1;
31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      while ( (next_pos = src.find_first_of('\n', cur_pos)) != std::string::npos) {
31846c82b4cd241a447834ed2f5a6be16777b7a990bBernhard Rosenkränzer        ALOGE("%03zd : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        cur_pos = next_pos + 1;
32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        line_number++;
32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
322e5160e7e59f96aa457e7a4217197150086e8b7caAndreas Gampe      ALOGE("%03zu : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GLint log_length = 0;
32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (log_length) {
32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        char* error_log = new char[log_length];
32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (error_log) {
32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetShaderInfoLog(shader, log_length, NULL, error_log);
33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          ALOGE("Shader compilation error %d:\n%s\n", shader_type, error_log);
33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          delete[] error_log;
33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glDeleteShader(shader);
33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      shader = 0;
33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return shader;
33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius RennGLuint ShaderProgram::LinkProgram(GLuint* shaders, GLuint count) {
34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLuint program = glCreateProgram();
34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (program) {
34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Attach all compiled shaders
34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    for (GLuint i = 0; i < count; ++i) {
34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glAttachShader(program, shaders[i]);
34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (GLEnv::CheckGLError("glAttachShader")) return 0;
34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Link
35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glLinkProgram(program);
35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Check for linking errors
35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    GLint linked = 0;
35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetProgramiv(program, GL_LINK_STATUS, &linked);
35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (linked != GL_TRUE) {
35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Log the linker error messages
35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GLint log_length = 0;
35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (log_length) {
36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        char* error_log = new char[log_length];
36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        if (error_log) {
36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          glGetProgramInfoLog(program, log_length, NULL, error_log);
36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          ALOGE("Program Linker Error:\n%s\n", error_log);
36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn          delete[] error_log;
36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        }
36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glDeleteProgram(program);
36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      program = 0;
37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return program;
37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::ScanUniforms() {
37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int uniform_count;
37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  int buffer_size;
37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLenum type;
37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint capacity;
38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetProgramiv(program_, GL_ACTIVE_UNIFORMS, &uniform_count);
38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetProgramiv(program_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &buffer_size);
38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::vector<GLchar> name(buffer_size);
38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < uniform_count; ++i) {
38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetActiveUniform(program_, i, buffer_size, NULL, &capacity, &type, &name[0]);
38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar uniform_id = glGetUniformLocation(program_, &name[0]);
38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    uniform_indices_[uniform_id] = i;
38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushCoords(ProgramVar attr, float* coords) {
39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // If the shader does not define these, we simply ignore the coordinates, and assume that the
39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // user is managing coordinates.
39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (attr >= 0) {
39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    const uint8_t* data = reinterpret_cast<const uint8_t*>(coords);
39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindBuffer(GL_ARRAY_BUFFER, 0);
39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glVertexAttribPointer(attr, 2, GL_FLOAT, false, 2 * sizeof(float), data);
39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glEnableVertexAttribArray(attr);
39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Pushing vertex coordinates");
39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushSourceCoords(float* coords) {
40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return PushCoords(tex_coord_attr, coords);
40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::PushTargetCoords(float* coords) {
40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return PushCoords(pos_coord_attr, coords);
41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennstd::string ShaderProgram::InputTextureUniformName(int index) {
41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  std::stringstream tex_name;
41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tex_name << "tex_sampler_" << index;
41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return tex_name.str();
41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::BindInputTextures(const std::vector<GLuint>& textures,
42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                      const std::vector<GLenum>& targets) {
42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (unsigned i = 0; i < textures.size(); ++i) {
42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Activate texture unit i
42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glActiveTexture(BaseTextureUnit() + i);
42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Activating Texture Unit"))
42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Bind our texture
42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBindTexture(targets[i], textures[i]);
42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("Binding texture %d", textures[i]);
43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Binding Texture"))
43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    // Set the texture handle in the shader to unit i
43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ProgramVar tex_var = GetUniform(InputTextureUniformName(i));
43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (tex_var >= 0) {
43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      glUniform1i(tex_var, i);
43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    } else {
43846c82b4cd241a447834ed2f5a6be16777b7a990bBernhard Rosenkränzer      ALOGE("ShaderProgram: Shader does not seem to support %zd number of "
43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn           "inputs! Missing uniform 'tex_sampler_%d'!", textures.size(), i);
44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    if (GLEnv::CheckGLError("Texture Variable Binding"))
44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      return false;
44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::UseProgram() {
45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (GLEnv::GetCurrentProgram() != program_) {
45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    LOG_FRAME("Using program %d", program_);
45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glUseProgram(program_);
45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return !GLEnv::CheckGLError("Use Program");
45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::RenderFrame(const std::vector<GLuint>& textures,
46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                const std::vector<GLenum>& targets) {
46165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Make sure we have enough texture units to accomodate the textures
46265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (textures.size() > static_cast<unsigned>(MaxTextureUnits())) {
46365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: Number of input textures is unsupported on this "
46465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "platform!");
46565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
46865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Prepare to render
46965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!BeginDraw()) {
47065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("ShaderProgram: couldn't initialize gl for drawing!");
47165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
47265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
47365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
47465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Bind input textures
47565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!BindInputTextures(textures, targets)) {
47665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("BindInputTextures failed");
47765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
47865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
47965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
48065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (LOG_EVERY_FRAME) {
48165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    int fbo, program, buffer;
48265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
48365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_CURRENT_PROGRAM, &program);
48465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
48565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGV("RenderFrame: fbo %d prog %d buff %d", fbo, program, buffer);
48665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
48765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
48865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Render!
48965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const bool requestTile = (tile_x_count_ != 1 || tile_y_count_ != 1);
49065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const bool success = (!requestTile || !manage_coordinates_  || vertex_count_ != 4)
49165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      ? Draw()
49265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      : DrawTiled();
49365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
49465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Pop vertex attributes
49565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  PopAttributes();
49665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
49765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return success && !GLEnv::CheckGLError("Rendering");
49865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
49965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::Draw() {
50165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (PushSourceCoords(source_coords_) && PushTargetCoords(target_coords_)) {
50265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glDrawArrays(draw_mode_, 0, vertex_count_);
50365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return true;
50465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
50565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return false;
50665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
50765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
50865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::DrawTiled() {
50965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Target coordinate step size
51065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  float s[8];
51165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  float t[8];
51265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
51365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Step sizes
51465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float xs = 1.0f / static_cast<float>(tile_x_count_);
51565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  const float ys = 1.0f / static_cast<float>(tile_y_count_);
51665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
51765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Tile drawing loop
51865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  for (int i = 0; i < tile_x_count_; ++i) {
51965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    for (int j = 0; j < tile_y_count_; ++j) {
52065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Current coordinates in unit rectangle
52165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const float x = i / static_cast<float>(tile_x_count_);
52265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      const float y = j / static_cast<float>(tile_y_count_);
52365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
52465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Source coords
52565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x, y, &s[0], &s[1]);
52665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x + xs, y, &s[2], &s[3]);
52765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x, y + ys, &s[4], &s[5]);
52865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(source_coords_, x + xs, y + ys, &s[6], &s[7]);
52965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
53065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      // Target coords
53165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x, y, &t[0], &t[1]);
53265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x + xs, y, &t[2], &t[3]);
53365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x, y + ys, &t[4], &t[5]);
53465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      GetTileCoords(target_coords_, x + xs, y + ys, &t[6], &t[7]);
53565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
53665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      if (PushSourceCoords(s) && PushTargetCoords(t)) {
53765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        glDrawArrays(draw_mode_, 0, vertex_count_);
53865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        Yield();
53965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      } else {
54065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn        return false;
54165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn      }
54265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    }
54365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
54465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
54565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
54665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
54765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::Yield() {
54865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glFinish();
54965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
55065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::BeginDraw() {
55265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Activate shader program
55365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (!UseProgram())
55465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
55565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Push vertex attributes
55765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  PushAttributes();
55865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
55965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Clear output, if requested
56065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (clears_) {
56165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glClearColor(clear_color_.red,
56265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.green,
56365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.blue,
56465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                 clear_color_.alpha);
56565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glClear(GL_COLOR_BUFFER_BIT);
56665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
56765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
56865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  // Enable/Disable blending
56965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (blending_) {
57065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glEnable(GL_BLEND);
57165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    glBlendFunc(sfactor_, dfactor_);
57265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  } else glDisable(GL_BLEND);
57365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
57465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
57565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
57665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
57765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxVaryingCount() {
57865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  GLint result;
57965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
58065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return result;
58165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
58265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
58365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennint ShaderProgram::MaxTextureUnits() {
58465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
58565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
58665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
58765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetDrawMode(GLenum mode) {
58865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  draw_mode_ = mode;
58965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
59065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetClearsOutput(bool clears) {
59265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clears_ = clears;
59365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
59465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
59565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetClearColor(float red, float green, float blue, float alpha) {
59665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.red = red;
59765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.green = green;
59865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.blue = blue;
59965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  clear_color_.alpha = alpha;
60065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
60165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
60265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennvoid ShaderProgram::SetTileCounts(int x_count, int y_count) {
60365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tile_x_count_ = x_count;
60465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  tile_y_count_ = y_count;
60565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
60665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
60765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn// Variable Value Setting Helpers //////////////////////////////////////////////
60865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckValueCount(const std::string& var_type,
60965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    const std::string& var_name,
61065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int expected_count,
61165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int components,
61265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn                                    int value_size) {
61365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  if (expected_count != (value_size / components)) {
61465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    ALOGE("Shader Program: %s Value Error (%s): Expected value length %d "
61565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         "(%d components), but received length of %d (%d components)!",
61665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         var_type.c_str(), var_name.c_str(),
61765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         expected_count, components * expected_count,
61865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn         value_size / components, value_size);
61965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn    return false;
62065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  }
62165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn  return true;
62265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn}
62365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn
62465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennbool ShaderProgram::CheckValueMult(const std::string& var_type,
62565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9