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