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
30namespace android {
31namespace filterfw {
32
33static 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.
45static 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 /////////////////////////////////////////////////
56ShaderProgram::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 ////////////////////////////////////////////////
70ShaderProgram::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
92ShaderProgram::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
116ShaderProgram::~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
130void 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
156ShaderProgram* 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
169bool ShaderProgram::IsVarValid(ProgramVar var) {
170  return var != -1;
171}
172
173bool 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
217bool 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
223void 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
231void 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
239void 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
247void 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
255bool 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
296GLuint 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
341GLuint 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
375void 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
390bool 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
403bool ShaderProgram::PushSourceCoords(float* coords) {
404  ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
405  return PushCoords(tex_coord_attr, coords);
406}
407
408bool ShaderProgram::PushTargetCoords(float* coords) {
409  ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
410  return PushCoords(pos_coord_attr, coords);
411}
412
413std::string ShaderProgram::InputTextureUniformName(int index) {
414  std::stringstream tex_name;
415  tex_name << "tex_sampler_" << index;
416  return tex_name.str();
417}
418
419bool 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
450bool 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
459bool 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
500bool 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
508bool 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
547void ShaderProgram::Yield() {
548  glFinish();
549}
550
551bool 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
577int ShaderProgram::MaxVaryingCount() {
578  GLint result;
579  glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
580  return result;
581}
582
583int ShaderProgram::MaxTextureUnits() {
584  return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
585}
586
587void ShaderProgram::SetDrawMode(GLenum mode) {
588  draw_mode_ = mode;
589}
590
591void ShaderProgram::SetClearsOutput(bool clears) {
592  clears_ = clears;
593}
594
595void 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
602void 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 //////////////////////////////////////////////
608bool 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
624bool 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
637bool 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 ////////////////////////////////////////////////////////////////////
646bool 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
654int 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
663ProgramVar 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
671bool 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
683bool 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
695bool 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
746bool 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
809bool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) {
810  return SetUniformValue(var, &values[0], values.size());
811}
812
813bool ShaderProgram::SetUniformValue(ProgramVar var,
814                                    const std::vector<float>& values) {
815  return SetUniformValue(var, &values[0], values.size());
816}
817
818bool 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
831Value 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
923GLuint ShaderProgram::IndexOfUniform(ProgramVar var) {
924  return uniform_indices_[var];
925}
926
927// Attributes //////////////////////////////////////////////////////////////////////////////////////
928int ShaderProgram::MaxAttributeCount() {
929  GLint result;
930  glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result);
931  return result;
932}
933
934ProgramVar 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
944bool 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
970bool 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
995bool ShaderProgram::SetAttributeValues(ProgramVar var,
996                                       const std::vector<float>& data,
997                                       int components) {
998  return SetAttributeValues(var, &data[0], data.size(), components);
999}
1000
1001bool 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
1038bool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
1039  if (attrib.index >= 0) {
1040    attrib_values_[attrib.index] = attrib;
1041    return true;
1042  }
1043  return false;
1044}
1045
1046bool 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
1102bool 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
1114void ShaderProgram::SetVertexCount(int count) {
1115  vertex_count_ = count;
1116}
1117
1118} // namespace filterfw
1119} // namespace android
1120