Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "base/logging.h"
     18 
     19 #include "core/geometry.h"
     20 #include "core/gl_buffer_interface.h"
     21 #include "core/gl_env.h"
     22 #include "core/gl_frame.h"
     23 #include "core/shader_program.h"
     24 #include "core/vertex_frame.h"
     25 
     26 #include <string>
     27 #include <sstream>
     28 #include <vector>
     29 
     30 namespace android {
     31 namespace filterfw {
     32 
     33 // VBO attachment keys
     34 static const int kDefaultVboKey = 1;
     35 
     36 static const char* s_default_vertex_shader_source_ =
     37   "attribute vec4 a_position;\n"
     38   "attribute vec2 a_texcoord;\n"
     39   "varying vec2 v_texcoord;\n"
     40   "void main() {\n"
     41   "  gl_Position = a_position;\n"
     42   "  v_texcoord = a_texcoord;\n"
     43   "}\n";
     44 
     45 // Helper Functions ////////////////////////////////////////////////////////////
     46 // Maps coordinates x,y in the unit rectangle over to the quadrangle specified
     47 // by the four points in b. The result coordinates are written to xt and yt.
     48 static void GetTileCoords(const float* b, float x, float y, float* xt, float* yt) {
     49   const float w0 =  (1.0f - x) * (1.0f - y);
     50   const float w1 =  x * (1.0f - y);
     51   const float w2 =  (1.0f - x) * y;
     52   const float w3 =  x * y;
     53 
     54   *xt = w0 * b[0] + w1 * b[2] + w2 * b[4] + w3 * b[6];
     55   *yt = w0 * b[1] + w1 * b[3] + w2 * b[5] + w3 * b[7];
     56 }
     57 
     58 static inline float AdjustRatio(float current, float next) {
     59   return (current + next) / 2.0;
     60 }
     61 
     62 // VertexAttrib implementation /////////////////////////////////////////////////
     63 ShaderProgram::VertexAttrib::VertexAttrib()
     64   : is_const(true),
     65     index(-1),
     66     normalized(false),
     67     stride(0),
     68     components(0),
     69     offset(0),
     70     type(GL_FLOAT),
     71     vbo(0),
     72     values(NULL),
     73     owned_data(NULL) {
     74 }
     75 
     76 // ShaderProgram implementation ////////////////////////////////////////////////
     77 ShaderProgram::ShaderProgram(GLEnv* gl_env, const std::string& fragment_shader)
     78   : fragment_shader_source_(fragment_shader),
     79     vertex_shader_source_(s_default_vertex_shader_source_),
     80     fragment_shader_(0),
     81     vertex_shader_(0),
     82     program_(0),
     83     gl_env_(gl_env),
     84     base_texture_unit_(GL_TEXTURE0),
     85     source_coords_(NULL),
     86     target_coords_(NULL),
     87     manage_coordinates_(false),
     88     tile_x_count_(1),
     89     tile_y_count_(1),
     90     vertex_count_(4),
     91     draw_mode_(GL_TRIANGLE_STRIP),
     92     clears_(false),
     93     blending_(false),
     94     sfactor_(GL_SRC_ALPHA),
     95     dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
     96   SetDefaultCoords();
     97 }
     98 
     99 ShaderProgram::ShaderProgram(GLEnv* gl_env,
    100                              const std::string& vertex_shader,
    101                              const std::string& fragment_shader)
    102   : fragment_shader_source_(fragment_shader),
    103     vertex_shader_source_(vertex_shader),
    104     fragment_shader_(0),
    105     vertex_shader_(0),
    106     program_(0),
    107     gl_env_(gl_env),
    108     base_texture_unit_(GL_TEXTURE0),
    109     source_coords_(NULL),
    110     target_coords_(NULL),
    111     manage_coordinates_(false),
    112     tile_x_count_(1),
    113     tile_y_count_(1),
    114     vertex_count_(4),
    115     draw_mode_(GL_TRIANGLE_STRIP),
    116     clears_(false),
    117     blending_(false),
    118     sfactor_(GL_SRC_ALPHA),
    119     dfactor_(GL_ONE_MINUS_SRC_ALPHA) {
    120   SetDefaultCoords();
    121 }
    122 
    123 ShaderProgram::~ShaderProgram() {
    124   // Delete our vertex data
    125   delete[] source_coords_;
    126   delete[] target_coords_;
    127 
    128   // Delete any owned attribute data
    129   VertexAttribMap::const_iterator iter;
    130   for (iter = attrib_values_.begin(); iter != attrib_values_.end(); ++iter) {
    131     const VertexAttrib& attrib = iter->second;
    132     if (attrib.owned_data)
    133       delete[] attrib.owned_data;
    134   }
    135 }
    136 
    137 void ShaderProgram::SetDefaultCoords() {
    138   if (!source_coords_)
    139     source_coords_ = new float[8];
    140   if (!target_coords_)
    141     target_coords_ = new float[8];
    142 
    143   source_coords_[0] = 0.0f;
    144   source_coords_[1] = 0.0f;
    145   source_coords_[2] = 1.0f;
    146   source_coords_[3] = 0.0f;
    147   source_coords_[4] = 0.0f;
    148   source_coords_[5] = 1.0f;
    149   source_coords_[6] = 1.0f;
    150   source_coords_[7] = 1.0f;
    151 
    152   target_coords_[0] = -1.0f;
    153   target_coords_[1] = -1.0f;
    154   target_coords_[2] =  1.0f;
    155   target_coords_[3] = -1.0f;
    156   target_coords_[4] = -1.0f;
    157   target_coords_[5] =  1.0f;
    158   target_coords_[6] =  1.0f;
    159   target_coords_[7] =  1.0f;
    160 
    161 }
    162 
    163 ShaderProgram* ShaderProgram::CreateIdentity(GLEnv* gl_env) {
    164   const char* s_id_fragment_shader =
    165     "precision mediump float;\n"
    166     "uniform sampler2D tex_sampler_0;\n"
    167     "varying vec2 v_texcoord;\n"
    168     "void main() {\n"
    169     "  gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n"
    170     "}\n";
    171   ShaderProgram* result = new ShaderProgram(gl_env, s_id_fragment_shader);
    172   result->CompileAndLink();
    173   return result;
    174 }
    175 
    176 bool ShaderProgram::IsVarValid(ProgramVar var) {
    177   return var != -1;
    178 }
    179 
    180 bool ShaderProgram::Process(const std::vector<const GLTextureHandle*>& input,
    181                             GLFrameBufferHandle* output) {
    182   // TODO: This can be optimized: If the input and output are the same, as in
    183   // the last iteration (typical of a multi-pass filter), a lot of this setup
    184   // may be skipped.
    185 
    186   // Abort if program did not successfully compile and link
    187   if (!IsExecutable()) {
    188     LOGE("ShaderProgram: unexecutable program!");
    189     return false;
    190   }
    191 
    192   // Focus the FBO of the output
    193   if (!output->FocusFrameBuffer()) {
    194     LOGE("Unable to focus frame buffer");
    195     return false;
    196   }
    197 
    198   // Get all required textures
    199   std::vector<GLuint> textures;
    200   std::vector<GLenum> targets;
    201   for (unsigned i = 0; i < input.size(); ++i) {
    202     // Get the current input frame and make sure it is a GL frame
    203     if (input[i]) {
    204       // Get the texture bound to that frame
    205       const GLuint tex_id = input[i]->GetTextureId();
    206       const GLenum target = input[i]->GetTextureTarget();
    207       if (tex_id == 0) {
    208         LOGE("ShaderProgram: invalid texture id at input: %d!", i);
    209         return false;
    210       }
    211       textures.push_back(tex_id);
    212       targets.push_back(target);
    213     }
    214   }
    215 
    216   // And render!
    217   if (!RenderFrame(textures, targets)) {
    218     LOGE("Unable to render frame");
    219     return false;
    220   }
    221   return true;
    222 }
    223 
    224 bool ShaderProgram::Process(const std::vector<const GLFrame*>& input, GLFrame* output) {
    225   std::vector<const GLTextureHandle*> textures(input.size());
    226   std::copy(input.begin(), input.end(), textures.begin());
    227   return Process(textures, output);
    228 }
    229 
    230 void ShaderProgram::SetSourceRect(float x, float y, float width, float height) {
    231   Quad quad(Point(x,          y),
    232             Point(x + width,  y),
    233             Point(x,          y + height),
    234             Point(x + width,  y + height));
    235   SetSourceRegion(quad);
    236 }
    237 
    238 void ShaderProgram::SetSourceRegion(const Quad& quad) {
    239   int index = 0;
    240   for (int i = 0; i < 4; ++i, index += 2) {
    241     source_coords_[index]   = quad.point(i).x();
    242     source_coords_[index+1] = quad.point(i).y();
    243   }
    244 }
    245 
    246 void ShaderProgram::SetTargetRect(float x, float y, float width, float height) {
    247   Quad quad(Point(x,          y),
    248             Point(x + width,  y),
    249             Point(x,          y + height),
    250             Point(x + width,  y + height));
    251   SetTargetRegion(quad);
    252 }
    253 
    254 void ShaderProgram::SetTargetRegion(const Quad& quad) {
    255   int index = 0;
    256   for (int i = 0; i < 4; ++i, index += 2) {
    257     target_coords_[index]   = (quad.point(i).x() * 2.0) - 1.0;
    258     target_coords_[index+1] = (quad.point(i).y() * 2.0) - 1.0;
    259   }
    260 }
    261 
    262 bool ShaderProgram::CompileAndLink() {
    263   // Make sure we haven't compiled and linked already
    264   if (vertex_shader_ != 0 || fragment_shader_ != 0 || program_ != 0) {
    265     LOGE("Attempting to re-compile shaders!");
    266     return false;
    267   }
    268 
    269   // Compile vertex shader
    270   vertex_shader_ = CompileShader(GL_VERTEX_SHADER,
    271                                  vertex_shader_source_.c_str());
    272   if (!vertex_shader_) {
    273     LOGE("Shader compilation failed!");
    274     return false;
    275   }
    276 
    277   // Compile fragment shader
    278   fragment_shader_ = CompileShader(GL_FRAGMENT_SHADER,
    279                                    fragment_shader_source_.c_str());
    280   if (!fragment_shader_)
    281     return false;
    282 
    283   // Link
    284   GLuint shaders[2] = { vertex_shader_, fragment_shader_ };
    285   program_ = LinkProgram(shaders, 2);
    286 
    287   // Scan for all uniforms in the program
    288   ScanUniforms();
    289 
    290   // Check if we manage all coordinates
    291   if (program_ != 0) {
    292     ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
    293     ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
    294     manage_coordinates_ = (tex_coord_attr >= 0 && pos_coord_attr >= 0);
    295   } else {
    296     LOGE("Could not link shader program!");
    297     return false;
    298   }
    299 
    300   return true;
    301 }
    302 
    303 GLuint ShaderProgram::CompileShader(GLenum shader_type, const char* source) {
    304   LOG_FRAME("Compiling source:\n[%s]", source);
    305 
    306   // Create shader
    307   GLuint shader = glCreateShader(shader_type);
    308   if (shader) {
    309     // Compile source
    310     glShaderSource(shader, 1, &source, NULL);
    311     glCompileShader(shader);
    312 
    313     // Check for compilation errors
    314     GLint compiled = 0;
    315     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    316     if (!compiled) {
    317       // Log the compilation error messages
    318       LOGE("Problem compiling shader! Source:");
    319       LOGE("%s", source);
    320       std::string src(source);
    321       unsigned int cur_pos = 0;
    322       unsigned int next_pos = 0;
    323       int line_number = 1;
    324       while ( (next_pos = src.find_first_of('\n', cur_pos)) != std::string::npos) {
    325         LOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
    326         cur_pos = next_pos + 1;
    327         line_number++;
    328       }
    329       LOGE("%03d : %s", line_number, src.substr(cur_pos, next_pos-cur_pos).c_str());
    330 
    331       GLint log_length = 0;
    332       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
    333       if (log_length) {
    334         char* error_log = new char[log_length];
    335         if (error_log) {
    336           glGetShaderInfoLog(shader, log_length, NULL, error_log);
    337           LOGE("Shader compilation error %d:\n%s\n", shader_type, error_log);
    338           delete[] error_log;
    339         }
    340       }
    341       glDeleteShader(shader);
    342       shader = 0;
    343     }
    344   }
    345   return shader;
    346 }
    347 
    348 GLuint ShaderProgram::LinkProgram(GLuint* shaders, GLuint count) {
    349   GLuint program = glCreateProgram();
    350   if (program) {
    351     // Attach all compiled shaders
    352     for (GLuint i = 0; i < count; ++i) {
    353       glAttachShader(program, shaders[i]);
    354       if (GLEnv::CheckGLError("glAttachShader")) return 0;
    355     }
    356 
    357     // Link
    358     glLinkProgram(program);
    359 
    360     // Check for linking errors
    361     GLint linked = 0;
    362     glGetProgramiv(program, GL_LINK_STATUS, &linked);
    363     if (linked != GL_TRUE) {
    364       // Log the linker error messages
    365       GLint log_length = 0;
    366       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
    367       if (log_length) {
    368         char* error_log = new char[log_length];
    369         if (error_log) {
    370           glGetProgramInfoLog(program, log_length, NULL, error_log);
    371           LOGE("Program Linker Error:\n%s\n", error_log);
    372           delete[] error_log;
    373         }
    374       }
    375       glDeleteProgram(program);
    376       program = 0;
    377     }
    378   }
    379   return program;
    380 }
    381 
    382 void ShaderProgram::ScanUniforms() {
    383   int uniform_count;
    384   int buffer_size;
    385   GLenum type;
    386   GLint capacity;
    387   glGetProgramiv(program_, GL_ACTIVE_UNIFORMS, &uniform_count);
    388   glGetProgramiv(program_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &buffer_size);
    389   std::vector<GLchar> name(buffer_size);
    390   for (int i = 0; i < uniform_count; ++i) {
    391     glGetActiveUniform(program_, i, buffer_size, NULL, &capacity, &type, &name[0]);
    392     ProgramVar uniform_id = glGetUniformLocation(program_, &name[0]);
    393     uniform_indices_[uniform_id] = i;
    394   }
    395 }
    396 
    397 bool ShaderProgram::PushCoords(ProgramVar attr, float* coords) {
    398   // If the shader does not define these, we simply ignore the coordinates, and assume that the
    399   // user is managing coordinates.
    400   if (attr >= 0) {
    401     const uint8_t* data = reinterpret_cast<const uint8_t*>(coords);
    402     glBindBuffer(GL_ARRAY_BUFFER, 0);
    403     glVertexAttribPointer(attr, 2, GL_FLOAT, false, 2 * sizeof(float), data);
    404     glEnableVertexAttribArray(attr);
    405     return !GLEnv::CheckGLError("Pushing vertex coordinates");
    406   }
    407   return true;
    408 }
    409 
    410 bool ShaderProgram::PushSourceCoords(float* coords) {
    411   ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
    412   return PushCoords(tex_coord_attr, coords);
    413 }
    414 
    415 bool ShaderProgram::PushTargetCoords(float* coords) {
    416   ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
    417   return PushCoords(pos_coord_attr, coords);
    418 }
    419 
    420 std::string ShaderProgram::InputTextureUniformName(int index) {
    421   std::stringstream tex_name;
    422   tex_name << "tex_sampler_" << index;
    423   return tex_name.str();
    424 }
    425 
    426 bool ShaderProgram::BindInputTextures(const std::vector<GLuint>& textures,
    427                                       const std::vector<GLenum>& targets) {
    428   for (unsigned i = 0; i < textures.size(); ++i) {
    429     // Activate texture unit i
    430     glActiveTexture(BaseTextureUnit() + i);
    431     if (GLEnv::CheckGLError("Activating Texture Unit"))
    432       return false;
    433 
    434     // Bind our texture
    435     glBindTexture(targets[i], textures[i]);
    436     LOG_FRAME("Binding texture %d", textures[i]);
    437     if (GLEnv::CheckGLError("Binding Texture"))
    438       return false;
    439 
    440     // Set the texture handle in the shader to unit i
    441     ProgramVar tex_var = GetUniform(InputTextureUniformName(i));
    442     if (tex_var >= 0) {
    443       glUniform1i(tex_var, i);
    444     } else {
    445       LOGE("ShaderProgram: Shader does not seem to support %d number of "
    446            "inputs! Missing uniform 'tex_sampler_%d'!", textures.size(), i);
    447       return false;
    448     }
    449 
    450     if (GLEnv::CheckGLError("Texture Variable Binding"))
    451       return false;
    452   }
    453 
    454   return true;
    455 }
    456 
    457 bool ShaderProgram::UseProgram() {
    458   if (GLEnv::GetCurrentProgram() != program_) {
    459     LOG_FRAME("Using program %d", program_);
    460     glUseProgram(program_);
    461     return !GLEnv::CheckGLError("Use Program");
    462   }
    463   return true;
    464 }
    465 
    466 bool ShaderProgram::RenderFrame(const std::vector<GLuint>& textures,
    467                                 const std::vector<GLenum>& targets) {
    468   // Make sure we have enough texture units to accomodate the textures
    469   if (textures.size() > static_cast<unsigned>(MaxTextureUnits())) {
    470     LOGE("ShaderProgram: Number of input textures is unsupported on this "
    471          "platform!");
    472     return false;
    473   }
    474 
    475   // Prepare to render
    476   if (!BeginDraw()) {
    477     LOGE("ShaderProgram: couldn't initialize gl for drawing!");
    478     return false;
    479   }
    480 
    481   // Bind input textures
    482   if (!BindInputTextures(textures, targets)) {
    483     LOGE("BindInputTextures failed");
    484     return false;
    485   }
    486 
    487   if (LOG_EVERY_FRAME) {
    488     int fbo, program, buffer;
    489     glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
    490     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
    491     glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer);
    492     LOGV("RenderFrame: fbo %d prog %d buff %d", fbo, program, buffer);
    493   }
    494 
    495   // Render!
    496   const bool requestTile = (tile_x_count_ != 1 || tile_y_count_ != 1);
    497   const bool success = (!requestTile || !manage_coordinates_  || vertex_count_ != 4)
    498       ? Draw()
    499       : DrawTiled();
    500 
    501   // Pop vertex attributes
    502   PopAttributes();
    503 
    504   return success && !GLEnv::CheckGLError("Rendering");
    505 }
    506 
    507 bool ShaderProgram::Draw() {
    508   if (PushSourceCoords(source_coords_) && PushTargetCoords(target_coords_)) {
    509     glDrawArrays(draw_mode_, 0, vertex_count_);
    510     return true;
    511   }
    512   return false;
    513 }
    514 
    515 bool ShaderProgram::DrawTiled() {
    516   // Target coordinate step size
    517   float s[8];
    518   float t[8];
    519 
    520   // Step sizes
    521   const float xs = 1.0f / static_cast<float>(tile_x_count_);
    522   const float ys = 1.0f / static_cast<float>(tile_y_count_);
    523 
    524   // Tile drawing loop
    525   for (int i = 0; i < tile_x_count_; ++i) {
    526     for (int j = 0; j < tile_y_count_; ++j) {
    527       // Current coordinates in unit rectangle
    528       const float x = i / static_cast<float>(tile_x_count_);
    529       const float y = j / static_cast<float>(tile_y_count_);
    530 
    531       // Source coords
    532       GetTileCoords(source_coords_, x, y, &s[0], &s[1]);
    533       GetTileCoords(source_coords_, x + xs, y, &s[2], &s[3]);
    534       GetTileCoords(source_coords_, x, y + ys, &s[4], &s[5]);
    535       GetTileCoords(source_coords_, x + xs, y + ys, &s[6], &s[7]);
    536 
    537       // Target coords
    538       GetTileCoords(target_coords_, x, y, &t[0], &t[1]);
    539       GetTileCoords(target_coords_, x + xs, y, &t[2], &t[3]);
    540       GetTileCoords(target_coords_, x, y + ys, &t[4], &t[5]);
    541       GetTileCoords(target_coords_, x + xs, y + ys, &t[6], &t[7]);
    542 
    543       if (PushSourceCoords(s) && PushTargetCoords(t)) {
    544         glDrawArrays(draw_mode_, 0, vertex_count_);
    545         Yield();
    546       } else {
    547         return false;
    548       }
    549     }
    550   }
    551   return true;
    552 }
    553 
    554 void ShaderProgram::Yield() {
    555   glFinish();
    556 }
    557 
    558 bool ShaderProgram::BeginDraw() {
    559   // Activate shader program
    560   if (!UseProgram())
    561     return false;
    562 
    563   // Push vertex attributes
    564   PushAttributes();
    565 
    566   // Clear output, if requested
    567   if (clears_) {
    568     glClearColor(clear_color_.red,
    569                  clear_color_.green,
    570                  clear_color_.blue,
    571                  clear_color_.alpha);
    572     glClear(GL_COLOR_BUFFER_BIT);
    573   }
    574 
    575   // Enable/Disable blending
    576   if (blending_) {
    577     glEnable(GL_BLEND);
    578     glBlendFunc(sfactor_, dfactor_);
    579   } else glDisable(GL_BLEND);
    580 
    581   return true;
    582 }
    583 
    584 int ShaderProgram::MaxVaryingCount() {
    585   GLint result;
    586   glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
    587   return result;
    588 }
    589 
    590 int ShaderProgram::MaxTextureUnits() {
    591   return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
    592 }
    593 
    594 void ShaderProgram::SetDrawMode(GLenum mode) {
    595   draw_mode_ = mode;
    596 }
    597 
    598 void ShaderProgram::SetClearsOutput(bool clears) {
    599   clears_ = clears;
    600 }
    601 
    602 void ShaderProgram::SetClearColor(float red, float green, float blue, float alpha) {
    603   clear_color_.red = red;
    604   clear_color_.green = green;
    605   clear_color_.blue = blue;
    606   clear_color_.alpha = alpha;
    607 }
    608 
    609 void ShaderProgram::SetTileCounts(int x_count, int y_count) {
    610   tile_x_count_ = x_count;
    611   tile_y_count_ = y_count;
    612 }
    613 
    614 // Variable Value Setting Helpers //////////////////////////////////////////////
    615 bool ShaderProgram::CheckValueCount(const std::string& var_type,
    616                                     const std::string& var_name,
    617                                     int expected_count,
    618                                     int components,
    619                                     int value_size) {
    620   if (expected_count != (value_size / components)) {
    621     LOGE("Shader Program: %s Value Error (%s): Expected value length %d "
    622          "(%d components), but received length of %d (%d components)!",
    623          var_type.c_str(), var_name.c_str(),
    624          expected_count, components * expected_count,
    625          value_size / components, value_size);
    626     return false;
    627   }
    628   return true;
    629 }
    630 
    631 bool ShaderProgram::CheckValueMult(const std::string& var_type,
    632                                    const std::string& var_name,
    633                                    int components,
    634                                    int value_size) {
    635   if (value_size % components != 0) {
    636     LOGE("Shader Program: %s Value Error (%s): Value must be multiple of %d, "
    637          "but %d elements were passed!", var_type.c_str(), var_name.c_str(),
    638          components, value_size);
    639     return false;
    640   }
    641   return true;
    642 }
    643 
    644 bool ShaderProgram::CheckVarValid(ProgramVar var) {
    645   if (!IsVarValid(var)) {
    646     LOGE("Shader Program: Attempting to access invalid variable!");
    647     return false;
    648   }
    649   return true;
    650 }
    651 
    652 // Uniforms ////////////////////////////////////////////////////////////////////
    653 bool ShaderProgram::CheckUniformValid(ProgramVar var) {
    654   if (!IsVarValid(var) || uniform_indices_.find(var) == uniform_indices_.end()) {
    655     LOGE("Shader Program: Attempting to access unknown uniform %d!", var);
    656     return false;
    657   }
    658   return true;
    659 }
    660 
    661 int ShaderProgram::MaxUniformCount() {
    662   // Here we return the minimum of the max uniform count for fragment and vertex
    663   // shaders.
    664   GLint count1, count2;
    665   glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &count1);
    666   glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &count2);
    667   return count1 < count2 ? count1 : count2;
    668 }
    669 
    670 ProgramVar ShaderProgram::GetUniform(const std::string& name) const {
    671   if (!IsExecutable()) {
    672     LOGE("ShaderProgram: Error: Must link program before querying uniforms!");
    673     return -1;
    674   }
    675   return glGetUniformLocation(program_, name.c_str());
    676 }
    677 
    678 bool ShaderProgram::SetUniformValue(ProgramVar var, int value) {
    679   if (!CheckVarValid(var))
    680     return false;
    681 
    682   // Uniforms are local to the currently used program.
    683   if (UseProgram()) {
    684     glUniform1i(var, value);
    685     return !GLEnv::CheckGLError("Set Uniform Value (int)");
    686   }
    687   return false;
    688 }
    689 
    690 bool ShaderProgram::SetUniformValue(ProgramVar var, float value) {
    691   if (!CheckVarValid(var))
    692     return false;
    693 
    694   // Uniforms are local to the currently used program.
    695   if (UseProgram()) {
    696     glUniform1f(var, value);
    697     return !GLEnv::CheckGLError("Set Uniform Value (float)");
    698   }
    699   return false;
    700 }
    701 
    702 bool ShaderProgram::SetUniformValue(ProgramVar var,
    703                                     const int* values,
    704                                     int count) {
    705   if (!CheckUniformValid(var))
    706     return false;
    707 
    708   // Make sure we have values at all
    709   if (count == 0)
    710     return false;
    711 
    712   // Uniforms are local to the currently used program.
    713   if (UseProgram()) {
    714     // Get uniform information
    715     GLint capacity;
    716     GLenum type;
    717     char name[128];
    718     glGetActiveUniform(program_, IndexOfUniform(var), 128, NULL, &capacity, &type, name);
    719 
    720     // Make sure passed values are compatible
    721     const int components = GLEnv::NumberOfComponents(type);
    722     if (!CheckValueCount("Uniform (int)", name, capacity, components, count)
    723     ||  !CheckValueMult ("Uniform (int)", name, components, count))
    724       return false;
    725 
    726     // Set value based on type
    727     const int n = count / components;
    728     switch(type) {
    729       case GL_INT:
    730         glUniform1iv(var, n, values);
    731         break;
    732 
    733       case GL_INT_VEC2:
    734         glUniform2iv(var, n, values);
    735         break;
    736 
    737       case GL_INT_VEC3:
    738         glUniform3iv(var, n, values);
    739         break;
    740 
    741       case GL_INT_VEC4:
    742         glUniform4iv(var, n, values);
    743         break;
    744 
    745       default:
    746         return false;
    747     };
    748     return !GLEnv::CheckGLError("Set Uniform Value");
    749   }
    750   return false;
    751 }
    752 
    753 bool ShaderProgram::SetUniformValue(ProgramVar var,
    754                                     const float* values,
    755                                     int count) {
    756   if (!CheckUniformValid(var))
    757     return false;
    758 
    759   // Make sure we have values at all
    760   if (count == 0)
    761     return false;
    762 
    763   // Uniforms are local to the currently used program.
    764   if (UseProgram()) {
    765     // Get uniform information
    766     GLint capacity;
    767     GLenum type;
    768     char name[128];
    769     glGetActiveUniform(program_, IndexOfUniform(var), 128, NULL, &capacity, &type, name);
    770 
    771     // Make sure passed values are compatible
    772     const int components = GLEnv::NumberOfComponents(type);
    773     if (!CheckValueCount("Uniform (float)", name, capacity, components, count)
    774     ||  !CheckValueMult ("Uniform (float)", name, components, count))
    775       return false;
    776 
    777     // Set value based on type
    778     const int n = count / components;
    779     switch(type) {
    780       case GL_FLOAT:
    781         glUniform1fv(var, n, values);
    782         break;
    783 
    784       case GL_FLOAT_VEC2:
    785         glUniform2fv(var, n, values);
    786         break;
    787 
    788       case GL_FLOAT_VEC3:
    789         glUniform3fv(var, n, values);
    790         break;
    791 
    792       case GL_FLOAT_VEC4:
    793         glUniform4fv(var, n, values);
    794         break;
    795 
    796       case GL_FLOAT_MAT2:
    797         glUniformMatrix2fv(var, n, GL_FALSE, values);
    798         break;
    799 
    800       case GL_FLOAT_MAT3:
    801         glUniformMatrix3fv(var, n, GL_FALSE, values);
    802         break;
    803 
    804       case GL_FLOAT_MAT4:
    805         glUniformMatrix4fv(var, n, GL_FALSE, values);
    806         break;
    807 
    808       default:
    809         return false;
    810     };
    811     return !GLEnv::CheckGLError("Set Uniform Value");
    812   }
    813   return false;
    814 }
    815 
    816 bool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) {
    817   return SetUniformValue(var, &values[0], values.size());
    818 }
    819 
    820 bool ShaderProgram::SetUniformValue(ProgramVar var,
    821                                     const std::vector<float>& values) {
    822   return SetUniformValue(var, &values[0], values.size());
    823 }
    824 
    825 bool ShaderProgram::SetUniformValue(const std::string& name, const Value& value) {
    826   if (ValueIsFloat(value))
    827     return SetUniformValue(GetUniform(name), GetFloatValue(value));
    828   else if (ValueIsInt(value))
    829     return SetUniformValue(GetUniform(name), GetIntValue(value));
    830   else if (ValueIsFloatArray(value))
    831     return SetUniformValue(GetUniform(name), GetFloatArrayValue(value), GetValueCount(value));
    832   else if (ValueIsIntArray(value))
    833     return SetUniformValue(GetUniform(name), GetIntArrayValue(value), GetValueCount(value));
    834   else
    835     return false;
    836 }
    837 
    838 Value ShaderProgram::GetUniformValue(const std::string& name) {
    839   ProgramVar var = GetUniform(name);
    840   if (CheckUniformValid(var)) {
    841     // Get uniform information
    842     GLint capacity;
    843     GLenum type;
    844     glGetActiveUniform(program_, IndexOfUniform(var), 0, NULL, &capacity, &type, NULL);
    845     if (!GLEnv::CheckGLError("Get Active Uniform")) {
    846       // Get value based on type, and wrap in value object
    847       switch(type) {
    848         case GL_INT: {
    849           int value;
    850           glGetUniformiv(program_, var, &value);
    851           return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntValue(value)
    852                                                           : MakeNullValue();
    853         } break;
    854 
    855         case GL_INT_VEC2: {
    856           int value[2];
    857           glGetUniformiv(program_, var, &value[0]);
    858           return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 2)
    859                                                           : MakeNullValue();
    860         } break;
    861 
    862         case GL_INT_VEC3: {
    863           int value[3];
    864           glGetUniformiv(program_, var, &value[0]);
    865           return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 3)
    866                                                           : MakeNullValue();
    867         } break;
    868 
    869         case GL_INT_VEC4: {
    870           int value[4];
    871           glGetUniformiv(program_, var, &value[0]);
    872           return !GLEnv::CheckGLError("GetVariableValue") ? MakeIntArrayValue(value, 4)
    873                                                           : MakeNullValue();
    874         } break;
    875 
    876         case GL_FLOAT: {
    877           float value;
    878           glGetUniformfv(program_, var, &value);
    879           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatValue(value)
    880                                                           : MakeNullValue();
    881         } break;
    882 
    883         case GL_FLOAT_VEC2: {
    884           float value[2];
    885           glGetUniformfv(program_, var, &value[0]);
    886           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 2)
    887                                                           : MakeNullValue();
    888         } break;
    889 
    890         case GL_FLOAT_VEC3: {
    891           float value[3];
    892           glGetUniformfv(program_, var, &value[0]);
    893           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 3)
    894                                                           : MakeNullValue();
    895         } break;
    896 
    897         case GL_FLOAT_VEC4: {
    898           float value[4];
    899           glGetUniformfv(program_, var, &value[0]);
    900           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 4)
    901                                                           : MakeNullValue();
    902         } break;
    903 
    904         case GL_FLOAT_MAT2: {
    905           float value[4];
    906           glGetUniformfv(program_, var, &value[0]);
    907           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 4)
    908                                                           : MakeNullValue();
    909         } break;
    910 
    911         case GL_FLOAT_MAT3: {
    912           float value[9];
    913           glGetUniformfv(program_, var, &value[0]);
    914           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 9)
    915                                                           : MakeNullValue();
    916         } break;
    917 
    918         case GL_FLOAT_MAT4: {
    919           float value[16];
    920           glGetUniformfv(program_, var, &value[0]);
    921           return !GLEnv::CheckGLError("GetVariableValue") ? MakeFloatArrayValue(value, 16)
    922                                                           : MakeNullValue();
    923         } break;
    924       }
    925     }
    926   }
    927   return MakeNullValue();
    928 }
    929 
    930 GLuint ShaderProgram::IndexOfUniform(ProgramVar var) {
    931   return uniform_indices_[var];
    932 }
    933 
    934 // Attributes //////////////////////////////////////////////////////////////////////////////////////
    935 int ShaderProgram::MaxAttributeCount() {
    936   GLint result;
    937   glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result);
    938   return result;
    939 }
    940 
    941 ProgramVar ShaderProgram::GetAttribute(const std::string& name) const {
    942   if (!IsExecutable()) {
    943     LOGE("ShaderProgram: Error: Must link program before querying attributes!");
    944     return -1;
    945   } else if (name == PositionAttributeName() || name == TexCoordAttributeName()) {
    946     LOGW("ShaderProgram: Attempting to overwrite internal vertex attribute '%s'!", name.c_str());
    947   }
    948   return glGetAttribLocation(program_, name.c_str());
    949 }
    950 
    951 bool ShaderProgram::SetAttributeValues(ProgramVar var,
    952                                        const VertexFrame* vbo,
    953                                        GLenum type,
    954                                        int components,
    955                                        int stride,
    956                                        int offset,
    957                                        bool normalize) {
    958   if (!CheckVarValid(var))
    959     return false;
    960 
    961   if (vbo) {
    962     VertexAttrib attrib;
    963     attrib.is_const = false;
    964     attrib.index = var;
    965     attrib.components = components;
    966     attrib.normalized = normalize;
    967     attrib.stride = stride;
    968     attrib.type = type;
    969     attrib.vbo = vbo->GetVboId();
    970     attrib.offset = offset;
    971 
    972     return StoreAttribute(attrib);
    973   }
    974   return false;
    975 }
    976 
    977 bool ShaderProgram::SetAttributeValues(ProgramVar var,
    978                                        const uint8_t* data,
    979                                        GLenum type,
    980                                        int components,
    981                                        int stride,
    982                                        int offset,
    983                                        bool normalize) {
    984   if (!CheckVarValid(var))
    985     return false;
    986 
    987   if (data) {
    988     VertexAttrib attrib;
    989     attrib.is_const = false;
    990     attrib.index = var;
    991     attrib.components = components;
    992     attrib.normalized = normalize;
    993     attrib.stride = stride;
    994     attrib.type = type;
    995     attrib.values = data + offset;
    996 
    997     return StoreAttribute(attrib);
    998   }
    999   return false;
   1000 }
   1001 
   1002 bool ShaderProgram::SetAttributeValues(ProgramVar var,
   1003                                        const std::vector<float>& data,
   1004                                        int components) {
   1005   return SetAttributeValues(var, &data[0], data.size(), components);
   1006 }
   1007 
   1008 bool ShaderProgram::SetAttributeValues(ProgramVar var,
   1009                                        const float* data,
   1010                                        int total,
   1011                                        int components) {
   1012   if (!CheckVarValid(var))
   1013     return false;
   1014 
   1015   // Make sure the passed data vector has a valid size
   1016   if (total  % components != 0) {
   1017     LOGE("ShaderProgram: Invalid attribute vector given! Specified a component "
   1018          "count of %d, but passed a non-multiple vector of size %d!",
   1019          components, total);
   1020     return false;
   1021   }
   1022 
   1023   // Copy the data to a buffer we own
   1024   float* data_cpy = new float[total];
   1025   memcpy(data_cpy, data, sizeof(float) * total);
   1026 
   1027   // Store the attribute
   1028   VertexAttrib attrib;
   1029   attrib.is_const = false;
   1030   attrib.index = var;
   1031   attrib.components = components;
   1032   attrib.normalized = false;
   1033   attrib.stride = components * sizeof(float);
   1034   attrib.type = GL_FLOAT;
   1035   attrib.values = data_cpy;
   1036   attrib.owned_data = data_cpy; // Marks this for deletion later on
   1037 
   1038   return StoreAttribute(attrib);
   1039 }
   1040 
   1041 bool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
   1042   if (attrib.index >= 0) {
   1043     attrib_values_[attrib.index] = attrib;
   1044     return true;
   1045   }
   1046   return false;
   1047 }
   1048 
   1049 bool ShaderProgram::PushAttributes() {
   1050   for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
   1051        iter != attrib_values_.end();
   1052        ++iter) {
   1053     const VertexAttrib& attrib = iter->second;
   1054 
   1055     if (attrib.is_const) {
   1056       // Set constant attribute values (must be specified as host values)
   1057       if (!attrib.values)
   1058         return false;
   1059 
   1060       const float* values = reinterpret_cast<const float*>(attrib.values);
   1061       switch (attrib.components) {
   1062         case 1: glVertexAttrib1fv(attrib.index, values); break;
   1063         case 2: glVertexAttrib2fv(attrib.index, values); break;
   1064         case 3: glVertexAttrib3fv(attrib.index, values); break;
   1065         case 4: glVertexAttrib4fv(attrib.index, values); break;
   1066         default: return false;
   1067       }
   1068       glDisableVertexAttribArray(attrib.index);
   1069     } else {
   1070       // Set per-vertex values
   1071       if (attrib.values) {
   1072         // Make sure no buffer is bound and set attribute
   1073         glBindBuffer(GL_ARRAY_BUFFER, 0);
   1074 
   1075         glVertexAttribPointer(attrib.index,
   1076                               attrib.components,
   1077                               attrib.type,
   1078                               attrib.normalized,
   1079                               attrib.stride,
   1080                               attrib.values);
   1081       } else if (attrib.vbo) {
   1082         // Bind VBO and set attribute
   1083         glBindBuffer(GL_ARRAY_BUFFER, attrib.vbo);
   1084 
   1085         glVertexAttribPointer(attrib.index,
   1086                               attrib.components,
   1087                               attrib.type,
   1088                               attrib.normalized,
   1089                               attrib.stride,
   1090                               reinterpret_cast<const void*>(attrib.offset));
   1091       } else {
   1092         return false;
   1093       }
   1094       glEnableVertexAttribArray(attrib.index);
   1095     }
   1096 
   1097     // Make sure everything worked
   1098     if (GLEnv::CheckGLError("Pushing Vertex Attributes"))
   1099       return false;
   1100   }
   1101 
   1102   return true;
   1103 }
   1104 
   1105 bool ShaderProgram::PopAttributes() {
   1106   // Disable vertex attributes
   1107   for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
   1108        iter != attrib_values_.end();
   1109        ++iter) {
   1110     glDisableVertexAttribArray(iter->second.index);
   1111   }
   1112   // Unbind buffer: Very important as this greatly affects what glVertexAttribPointer does!
   1113   glBindBuffer(GL_ARRAY_BUFFER, 0);
   1114   return !GLEnv::CheckGLError("Popping Vertex Attributes");
   1115 }
   1116 
   1117 void ShaderProgram::SetVertexCount(int count) {
   1118   vertex_count_ = count;
   1119 }
   1120 
   1121 } // namespace filterfw
   1122 } // namespace android
   1123