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