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. 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 ///////////////////////////////////////////////// 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 //////////////////////////////////////////////// 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 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 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 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 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 169 bool ShaderProgram::IsVarValid(ProgramVar var) { 170 return var != -1; 171 } 172 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 547 void ShaderProgram::Yield() { 548 glFinish(); 549 } 550 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 577 int ShaderProgram::MaxVaryingCount() { 578 GLint result; 579 glGetIntegerv(GL_MAX_VARYING_VECTORS, &result); 580 return result; 581 } 582 583 int ShaderProgram::MaxTextureUnits() { 584 return GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1; 585 } 586 587 void ShaderProgram::SetDrawMode(GLenum mode) { 588 draw_mode_ = mode; 589 } 590 591 void ShaderProgram::SetClearsOutput(bool clears) { 592 clears_ = clears; 593 } 594 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 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 ////////////////////////////////////////////// 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 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 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 //////////////////////////////////////////////////////////////////// 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 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 663 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 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 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 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 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 809 bool ShaderProgram::SetUniformValue(ProgramVar var, const std::vector<int>& values) { 810 return SetUniformValue(var, &values[0], values.size()); 811 } 812 813 bool ShaderProgram::SetUniformValue(ProgramVar var, 814 const std::vector<float>& values) { 815 return SetUniformValue(var, &values[0], values.size()); 816 } 817 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 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 923 GLuint ShaderProgram::IndexOfUniform(ProgramVar var) { 924 return uniform_indices_[var]; 925 } 926 927 // Attributes ////////////////////////////////////////////////////////////////////////////////////// 928 int ShaderProgram::MaxAttributeCount() { 929 GLint result; 930 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &result); 931 return result; 932 } 933 934 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 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 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 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 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 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 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 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 1110 void ShaderProgram::SetVertexCount(int count) { 1111 vertex_count_ = count; 1112 } 1113 1114 } // namespace filterfw 1115 } // namespace android 1116