shader_program.cpp revision 65953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9
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
33// VBO attachment keys
34static const int kDefaultVboKey = 1;
35
36static 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.
48static 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
58static inline float AdjustRatio(float current, float next) {
59  return (current + next) / 2.0;
60}
61
62// VertexAttrib implementation /////////////////////////////////////////////////
63ShaderProgram::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 ////////////////////////////////////////////////
77ShaderProgram::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
99ShaderProgram::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
123ShaderProgram::~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
137void 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
163ShaderProgram* 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
176bool ShaderProgram::IsVarValid(ProgramVar var) {
177  return var != -1;
178}
179
180bool 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    ALOGE("ShaderProgram: unexecutable program!");
189    return false;
190  }
191
192  // Focus the FBO of the output
193  if (!output->FocusFrameBuffer()) {
194    ALOGE("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        ALOGE("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    ALOGE("Unable to render frame");
219    return false;
220  }
221  return true;
222}
223
224bool 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
230void 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
238void 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
246void 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
254void 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
262bool ShaderProgram::CompileAndLink() {
263  // Make sure we haven't compiled and linked already
264  if (vertex_shader_ != 0 || fragment_shader_ != 0 || program_ != 0) {
265    ALOGE("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    ALOGE("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    ALOGE("Could not link shader program!");
297    return false;
298  }
299
300  return true;
301}
302
303GLuint 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      ALOGE("Problem compiling shader! Source:");
319      ALOGE("%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        ALOGE("%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      ALOGE("%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          ALOGE("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
348GLuint 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          ALOGE("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
382void 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
397bool 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
410bool ShaderProgram::PushSourceCoords(float* coords) {
411  ProgramVar tex_coord_attr = glGetAttribLocation(program_, TexCoordAttributeName().c_str());
412  return PushCoords(tex_coord_attr, coords);
413}
414
415bool ShaderProgram::PushTargetCoords(float* coords) {
416  ProgramVar pos_coord_attr = glGetAttribLocation(program_, PositionAttributeName().c_str());
417  return PushCoords(pos_coord_attr, coords);
418}
419
420std::string ShaderProgram::InputTextureUniformName(int index) {
421  std::stringstream tex_name;
422  tex_name << "tex_sampler_" << index;
423  return tex_name.str();
424}
425
426bool 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      ALOGE("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
457bool 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
466bool 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    ALOGE("ShaderProgram: Number of input textures is unsupported on this "
471         "platform!");
472    return false;
473  }
474
475  // Prepare to render
476  if (!BeginDraw()) {
477    ALOGE("ShaderProgram: couldn't initialize gl for drawing!");
478    return false;
479  }
480
481  // Bind input textures
482  if (!BindInputTextures(textures, targets)) {
483    ALOGE("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    ALOGV("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
507bool 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
515bool 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
554void ShaderProgram::Yield() {
555  glFinish();
556}
557
558bool 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
584int ShaderProgram::MaxVaryingCount() {
585  GLint result;
586  glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
587  return result;
588}
589
590int ShaderProgram::MaxTextureUnits() {
591  return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
592}
593
594void ShaderProgram::SetDrawMode(GLenum mode) {
595  draw_mode_ = mode;
596}
597
598void ShaderProgram::SetClearsOutput(bool clears) {
599  clears_ = clears;
600}
601
602void 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
609void 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 //////////////////////////////////////////////
615bool 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    ALOGE("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
631bool 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    ALOGE("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
644bool ShaderProgram::CheckVarValid(ProgramVar var) {
645  if (!IsVarValid(var)) {
646    ALOGE("Shader Program: Attempting to access invalid variable!");
647    return false;
648  }
649  return true;
650}
651
652// Uniforms ////////////////////////////////////////////////////////////////////
653bool ShaderProgram::CheckUniformValid(ProgramVar var) {
654  if (!IsVarValid(var) || uniform_indices_.find(var) == uniform_indices_.end()) {
655    ALOGE("Shader Program: Attempting to access unknown uniform %d!", var);
656    return false;
657  }
658  return true;
659}
660
661int 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
670ProgramVar ShaderProgram::GetUniform(const std::string& name) const {
671  if (!IsExecutable()) {
672    ALOGE("ShaderProgram: Error: Must link program before querying uniforms!");
673    return -1;
674  }
675  return glGetUniformLocation(program_, name.c_str());
676}
677
678bool 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
690bool 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
702bool 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
753bool 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
816bool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) {
817  return SetUniformValue(var, &values[0], values.size());
818}
819
820bool ShaderProgram::SetUniformValue(ProgramVar var,
821                                    const std::vector<float>& values) {
822  return SetUniformValue(var, &values[0], values.size());
823}
824
825bool 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
838Value 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
930GLuint ShaderProgram::IndexOfUniform(ProgramVar var) {
931  return uniform_indices_[var];
932}
933
934// Attributes //////////////////////////////////////////////////////////////////////////////////////
935int ShaderProgram::MaxAttributeCount() {
936  GLint result;
937  glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result);
938  return result;
939}
940
941ProgramVar ShaderProgram::GetAttribute(const std::string& name) const {
942  if (!IsExecutable()) {
943    ALOGE("ShaderProgram: Error: Must link program before querying attributes!");
944    return -1;
945  } else if (name == PositionAttributeName() || name == TexCoordAttributeName()) {
946    ALOGW("ShaderProgram: Attempting to overwrite internal vertex attribute '%s'!", name.c_str());
947  }
948  return glGetAttribLocation(program_, name.c_str());
949}
950
951bool 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
977bool 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
1002bool ShaderProgram::SetAttributeValues(ProgramVar var,
1003                                       const std::vector<float>& data,
1004                                       int components) {
1005  return SetAttributeValues(var, &data[0], data.size(), components);
1006}
1007
1008bool 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    ALOGE("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
1041bool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
1042  if (attrib.index >= 0) {
1043    attrib_values_[attrib.index] = attrib;
1044    return true;
1045  }
1046  return false;
1047}
1048
1049bool 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
1105bool 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
1117void ShaderProgram::SetVertexCount(int count) {
1118  vertex_count_ = count;
1119}
1120
1121} // namespace filterfw
1122} // namespace android
1123