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