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.
GetTileCoords(const float * b,float x,float y,float * xt,float * 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 /////////////////////////////////////////////////
VertexAttrib()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 ////////////////////////////////////////////////
ShaderProgram(GLEnv * gl_env,const std::string & fragment_shader)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 
ShaderProgram(GLEnv * gl_env,const std::string & vertex_shader,const std::string & fragment_shader)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 
~ShaderProgram()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 
SetDefaultCoords()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 
CreateIdentity(GLEnv * gl_env)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 
IsVarValid(ProgramVar var)169 bool ShaderProgram::IsVarValid(ProgramVar var) {
170   return var != -1;
171 }
172 
Process(const std::vector<const GLTextureHandle * > & input,GLFrameBufferHandle * output)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 
Process(const std::vector<const GLFrame * > & input,GLFrame * output)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 
SetSourceRect(float x,float y,float width,float height)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 
SetSourceRegion(const Quad & quad)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 
SetTargetRect(float x,float y,float width,float height)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 
SetTargetRegion(const Quad & quad)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 
CompileAndLink()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 
CompileShader(GLenum shader_type,const char * source)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 
LinkProgram(GLuint * shaders,GLuint count)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 
ScanUniforms()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 
PushCoords(ProgramVar attr,float * coords)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 
PushSourceCoords(float * coords)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 
PushTargetCoords(float * coords)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 
InputTextureUniformName(int index)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 
BindInputTextures(const std::vector<GLuint> & textures,const std::vector<GLenum> & targets)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 
UseProgram()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 
RenderFrame(const std::vector<GLuint> & textures,const std::vector<GLenum> & targets)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 
Draw()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 
DrawTiled()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 
Yield()547 void ShaderProgram::Yield() {
548   glFinish();
549 }
550 
BeginDraw()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 
MaxVaryingCount()577 int ShaderProgram::MaxVaryingCount() {
578   GLint result;
579   glGetIntegerv(GL_MAX_VARYING_VECTORS, &result);
580   return result;
581 }
582 
MaxTextureUnits()583 int ShaderProgram::MaxTextureUnits() {
584   return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1;
585 }
586 
SetDrawMode(GLenum mode)587 void ShaderProgram::SetDrawMode(GLenum mode) {
588   draw_mode_ = mode;
589 }
590 
SetClearsOutput(bool clears)591 void ShaderProgram::SetClearsOutput(bool clears) {
592   clears_ = clears;
593 }
594 
SetClearColor(float red,float green,float blue,float alpha)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 
SetTileCounts(int x_count,int y_count)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 //////////////////////////////////////////////
CheckValueCount(const std::string & var_type,const std::string & var_name,int expected_count,int components,int value_size)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 
CheckValueMult(const std::string & var_type,const std::string & var_name,int components,int value_size)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 
CheckVarValid(ProgramVar var)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 ////////////////////////////////////////////////////////////////////
CheckUniformValid(ProgramVar var)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 
MaxUniformCount()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 
GetUniform(const std::string & name) const663 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 
SetUniformValue(ProgramVar var,int value)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 
SetUniformValue(ProgramVar var,float value)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 
SetUniformValue(ProgramVar var,const int * values,int count)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 
SetUniformValue(ProgramVar var,const float * values,int count)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 
SetUniformValue(ProgramVar var,const std::vector<int> & values)809 bool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) {
810   return SetUniformValue(var, &values[0], values.size());
811 }
812 
SetUniformValue(ProgramVar var,const std::vector<float> & values)813 bool ShaderProgram::SetUniformValue(ProgramVar var,
814                                     const std::vector<float>& values) {
815   return SetUniformValue(var, &values[0], values.size());
816 }
817 
SetUniformValue(const std::string & name,const Value & value)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 
GetUniformValue(const std::string & name)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 
IndexOfUniform(ProgramVar var)923 GLuint ShaderProgram::IndexOfUniform(ProgramVar var) {
924   return uniform_indices_[var];
925 }
926 
927 // Attributes //////////////////////////////////////////////////////////////////////////////////////
MaxAttributeCount()928 int ShaderProgram::MaxAttributeCount() {
929   GLint result;
930   glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result);
931   return result;
932 }
933 
GetAttribute(const std::string & name) const934 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 
SetAttributeValues(ProgramVar var,const VertexFrame * vbo,GLenum type,int components,int stride,int offset,bool normalize)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 
SetAttributeValues(ProgramVar var,const uint8_t * data,GLenum type,int components,int stride,int offset,bool normalize)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 
SetAttributeValues(ProgramVar var,const std::vector<float> & data,int components)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 
SetAttributeValues(ProgramVar var,const float * data,int total,int components)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   return StoreAttribute(attrib);
1032 }
1033 
StoreAttribute(VertexAttrib attrib)1034 bool ShaderProgram::StoreAttribute(VertexAttrib attrib) {
1035   if (attrib.index >= 0) {
1036     attrib_values_[attrib.index] = attrib;
1037     return true;
1038   }
1039   return false;
1040 }
1041 
PushAttributes()1042 bool ShaderProgram::PushAttributes() {
1043   for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
1044        iter != attrib_values_.end();
1045        ++iter) {
1046     const VertexAttrib& attrib = iter->second;
1047 
1048     if (attrib.is_const) {
1049       // Set constant attribute values (must be specified as host values)
1050       if (!attrib.values)
1051         return false;
1052 
1053       const float* values = reinterpret_cast<const float*>(attrib.values);
1054       switch (attrib.components) {
1055         case 1: glVertexAttrib1fv(attrib.index, values); break;
1056         case 2: glVertexAttrib2fv(attrib.index, values); break;
1057         case 3: glVertexAttrib3fv(attrib.index, values); break;
1058         case 4: glVertexAttrib4fv(attrib.index, values); break;
1059         default: return false;
1060       }
1061       glDisableVertexAttribArray(attrib.index);
1062     } else {
1063       // Set per-vertex values
1064       if (attrib.values) {
1065         // Make sure no buffer is bound and set attribute
1066         glBindBuffer(GL_ARRAY_BUFFER, 0);
1067 
1068         glVertexAttribPointer(attrib.index,
1069                               attrib.components,
1070                               attrib.type,
1071                               attrib.normalized,
1072                               attrib.stride,
1073                               attrib.values);
1074       } else if (attrib.vbo) {
1075         // Bind VBO and set attribute
1076         glBindBuffer(GL_ARRAY_BUFFER, attrib.vbo);
1077 
1078         glVertexAttribPointer(attrib.index,
1079                               attrib.components,
1080                               attrib.type,
1081                               attrib.normalized,
1082                               attrib.stride,
1083                               reinterpret_cast<const void*>(attrib.offset));
1084       } else {
1085         return false;
1086       }
1087       glEnableVertexAttribArray(attrib.index);
1088     }
1089 
1090     // Make sure everything worked
1091     if (GLEnv::CheckGLError("Pushing Vertex Attributes"))
1092       return false;
1093   }
1094 
1095   return true;
1096 }
1097 
PopAttributes()1098 bool ShaderProgram::PopAttributes() {
1099   // Disable vertex attributes
1100   for (VertexAttribMap::const_iterator iter = attrib_values_.begin();
1101        iter != attrib_values_.end();
1102        ++iter) {
1103     glDisableVertexAttribArray(iter->second.index);
1104   }
1105   // Unbind buffer: Very important as this greatly affects what glVertexAttribPointer does!
1106   glBindBuffer(GL_ARRAY_BUFFER, 0);
1107   return !GLEnv::CheckGLError("Popping Vertex Attributes");
1108 }
1109 
SetVertexCount(int count)1110 void ShaderProgram::SetVertexCount(int count) {
1111   vertex_count_ = count;
1112 }
1113 
1114 } // namespace filterfw
1115 } // namespace android
1116