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