| // Copyright 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/output/program_binding.h" |
| |
| #include "base/debug/trace_event.h" |
| #include "cc/output/geometry_binding.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| |
| using gpu::gles2::GLES2Interface; |
| |
| namespace cc { |
| |
| ProgramBindingBase::ProgramBindingBase() |
| : program_(0), |
| vertex_shader_id_(0), |
| fragment_shader_id_(0), |
| initialized_(false) {} |
| |
| ProgramBindingBase::~ProgramBindingBase() { |
| // If you hit these asserts, you initialized but forgot to call Cleanup(). |
| DCHECK(!program_); |
| DCHECK(!vertex_shader_id_); |
| DCHECK(!fragment_shader_id_); |
| DCHECK(!initialized_); |
| } |
| |
| bool ProgramBindingBase::Init(GLES2Interface* context, |
| const std::string& vertex_shader, |
| const std::string& fragment_shader) { |
| TRACE_EVENT0("cc", "ProgramBindingBase::init"); |
| vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader); |
| if (!vertex_shader_id_) |
| return false; |
| |
| fragment_shader_id_ = |
| LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader); |
| if (!fragment_shader_id_) { |
| context->DeleteShader(vertex_shader_id_); |
| vertex_shader_id_ = 0; |
| return false; |
| } |
| |
| program_ = |
| CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_); |
| return !!program_; |
| } |
| |
| bool ProgramBindingBase::Link(GLES2Interface* context) { |
| context->LinkProgram(program_); |
| CleanupShaders(context); |
| if (!program_) |
| return false; |
| #ifndef NDEBUG |
| int linked = 0; |
| context->GetProgramiv(program_, GL_LINK_STATUS, &linked); |
| if (!linked) |
| return false; |
| #endif |
| return true; |
| } |
| |
| void ProgramBindingBase::Cleanup(GLES2Interface* context) { |
| initialized_ = false; |
| if (!program_) |
| return; |
| |
| DCHECK(context); |
| context->DeleteProgram(program_); |
| program_ = 0; |
| |
| CleanupShaders(context); |
| } |
| |
| unsigned ProgramBindingBase::LoadShader(GLES2Interface* context, |
| unsigned type, |
| const std::string& shader_source) { |
| unsigned shader = context->CreateShader(type); |
| if (!shader) |
| return 0u; |
| |
| const char* shader_source_str[] = { shader_source.data() }; |
| int shader_length[] = { static_cast<int>(shader_source.length()) }; |
| context->ShaderSource( |
| shader, 1, |
| shader_source_str, |
| shader_length); |
| context->CompileShader(shader); |
| #ifndef NDEBUG |
| int compiled = 0; |
| context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled); |
| if (!compiled) |
| return 0u; |
| #endif |
| return shader; |
| } |
| |
| unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context, |
| unsigned vertex_shader, |
| unsigned fragment_shader) { |
| unsigned program_object = context->CreateProgram(); |
| if (!program_object) |
| return 0; |
| |
| context->AttachShader(program_object, vertex_shader); |
| context->AttachShader(program_object, fragment_shader); |
| |
| // Bind the common attrib locations. |
| context->BindAttribLocation( |
| program_object, GeometryBinding::PositionAttribLocation(), "a_position"); |
| context->BindAttribLocation( |
| program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord"); |
| context->BindAttribLocation(program_object, |
| GeometryBinding::TriangleIndexAttribLocation(), |
| "a_index"); |
| |
| return program_object; |
| } |
| |
| void ProgramBindingBase::CleanupShaders(GLES2Interface* context) { |
| if (vertex_shader_id_) { |
| context->DeleteShader(vertex_shader_id_); |
| vertex_shader_id_ = 0; |
| } |
| if (fragment_shader_id_) { |
| context->DeleteShader(fragment_shader_id_); |
| fragment_shader_id_ = 0; |
| } |
| } |
| |
| } // namespace cc |