// 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 "cc/output/gl_renderer.h" // For the GLC() macro. #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" #include "third_party/khronos/GLES2/gl2.h" using WebKit::WebGraphicsContext3D; 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_); } void ProgramBindingBase::Init(WebGraphicsContext3D* 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_) { if (!IsContextLost(context)) LOG(ERROR) << "Failed to create vertex shader"; return; } fragment_shader_id_ = LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader); if (!fragment_shader_id_) { GLC(context, context->deleteShader(vertex_shader_id_)); vertex_shader_id_ = 0; if (!IsContextLost(context)) LOG(ERROR) << "Failed to create fragment shader"; return; } program_ = CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_); DCHECK(program_ || IsContextLost(context)); } void ProgramBindingBase::Link(WebGraphicsContext3D* context) { GLC(context, context->linkProgram(program_)); CleanupShaders(context); if (!program_) return; #ifndef NDEBUG int linked = 0; GLC(context, context->getProgramiv(program_, GL_LINK_STATUS, &linked)); if (!linked) { if (!IsContextLost(context)) LOG(ERROR) << "Failed to link shader program"; GLC(context, context->deleteProgram(program_)); } #endif } void ProgramBindingBase::Cleanup(WebGraphicsContext3D* context) { initialized_ = false; if (!program_) return; DCHECK(context); GLC(context, context->deleteProgram(program_)); program_ = 0; CleanupShaders(context); } unsigned ProgramBindingBase::LoadShader(WebGraphicsContext3D* context, unsigned type, const std::string& shader_source) { unsigned shader = context->createShader(type); if (!shader) return 0; GLC(context, context->shaderSource(shader, shader_source.data())); GLC(context, context->compileShader(shader)); #ifndef NDEBUG int compiled = 0; GLC(context, context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled)); if (!compiled) { GLC(context, context->deleteShader(shader)); return 0; } #endif return shader; } unsigned ProgramBindingBase::CreateShaderProgram(WebGraphicsContext3D* context, unsigned vertex_shader, unsigned fragment_shader) { unsigned program_object = context->createProgram(); if (!program_object) { if (!IsContextLost(context)) LOG(ERROR) << "Failed to create shader program"; return 0; } GLC(context, context->attachShader(program_object, vertex_shader)); GLC(context, context->attachShader(program_object, fragment_shader)); // Bind the common attrib locations. GLC(context, context->bindAttribLocation(program_object, GeometryBinding::PositionAttribLocation(), "a_position")); GLC(context, context->bindAttribLocation(program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord")); GLC(context, context->bindAttribLocation( program_object, GeometryBinding::TriangleIndexAttribLocation(), "a_index")); return program_object; } void ProgramBindingBase::CleanupShaders(WebGraphicsContext3D* context) { if (vertex_shader_id_) { GLC(context, context->deleteShader(vertex_shader_id_)); vertex_shader_id_ = 0; } if (fragment_shader_id_) { GLC(context, context->deleteShader(fragment_shader_id_)); fragment_shader_id_ = 0; } } bool ProgramBindingBase::IsContextLost(WebGraphicsContext3D* context) { return (context->getGraphicsResetStatusARB() != GL_NO_ERROR); } } // namespace cc