blob: 5b7b13ee06daced13c42a48603bd28dfaa698062 [file] [log] [blame]
// 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