blob: ebad2e84b4b01156e4e2933a55af30aa06dff1c5 [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/trace_event/trace_event.h"
#include "cc/output/geometry_binding.h"
#include "gpu/GLES2/gl2extchromium.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) {
char buffer[1024];
context->GetProgramInfoLog(program_, sizeof(buffer), nullptr, buffer);
DLOG(ERROR) << "Error compiling shader: " << buffer;
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);
#if DCHECK_IS_ON()
int compiled = 0;
context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
char buffer[1024];
context->GetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
DLOG(ERROR) << "Error compiling shader: " << buffer
<< "\n shader program: " << shader_source;
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;
}
}
bool ProgramBindingBase::IsContextLost(GLES2Interface* context) {
return context->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
}
} // namespace cc