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