1// Copyright 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/output/program_binding.h"
6
7#include "base/debug/trace_event.h"
8#include "cc/output/geometry_binding.h"
9#include "gpu/command_buffer/client/gles2_interface.h"
10
11using gpu::gles2::GLES2Interface;
12
13namespace cc {
14
15ProgramBindingBase::ProgramBindingBase()
16    : program_(0),
17      vertex_shader_id_(0),
18      fragment_shader_id_(0),
19      initialized_(false) {}
20
21ProgramBindingBase::~ProgramBindingBase() {
22  // If you hit these asserts, you initialized but forgot to call Cleanup().
23  DCHECK(!program_);
24  DCHECK(!vertex_shader_id_);
25  DCHECK(!fragment_shader_id_);
26  DCHECK(!initialized_);
27}
28
29bool ProgramBindingBase::Init(GLES2Interface* context,
30                              const std::string& vertex_shader,
31                              const std::string& fragment_shader) {
32  TRACE_EVENT0("cc", "ProgramBindingBase::init");
33  vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
34  if (!vertex_shader_id_)
35    return false;
36
37  fragment_shader_id_ =
38      LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
39  if (!fragment_shader_id_) {
40    context->DeleteShader(vertex_shader_id_);
41    vertex_shader_id_ = 0;
42    return false;
43  }
44
45  program_ =
46      CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
47  return !!program_;
48}
49
50bool ProgramBindingBase::Link(GLES2Interface* context) {
51  context->LinkProgram(program_);
52  CleanupShaders(context);
53  if (!program_)
54    return false;
55#ifndef NDEBUG
56  int linked = 0;
57  context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
58  if (!linked)
59    return false;
60#endif
61  return true;
62}
63
64void ProgramBindingBase::Cleanup(GLES2Interface* context) {
65  initialized_ = false;
66  if (!program_)
67    return;
68
69  DCHECK(context);
70  context->DeleteProgram(program_);
71  program_ = 0;
72
73  CleanupShaders(context);
74}
75
76unsigned ProgramBindingBase::LoadShader(GLES2Interface* context,
77                                        unsigned type,
78                                        const std::string& shader_source) {
79  unsigned shader = context->CreateShader(type);
80  if (!shader)
81    return 0u;
82
83  const char* shader_source_str[] = { shader_source.data() };
84  int shader_length[] = { static_cast<int>(shader_source.length()) };
85  context->ShaderSource(
86      shader, 1,
87      shader_source_str,
88      shader_length);
89  context->CompileShader(shader);
90#ifndef NDEBUG
91  int compiled = 0;
92  context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
93  if (!compiled)
94    return 0u;
95#endif
96  return shader;
97}
98
99unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context,
100                                                 unsigned vertex_shader,
101                                                 unsigned fragment_shader) {
102  unsigned program_object = context->CreateProgram();
103  if (!program_object)
104    return 0;
105
106  context->AttachShader(program_object, vertex_shader);
107  context->AttachShader(program_object, fragment_shader);
108
109  // Bind the common attrib locations.
110  context->BindAttribLocation(
111      program_object, GeometryBinding::PositionAttribLocation(), "a_position");
112  context->BindAttribLocation(
113      program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord");
114  context->BindAttribLocation(program_object,
115                              GeometryBinding::TriangleIndexAttribLocation(),
116                              "a_index");
117
118  return program_object;
119}
120
121void ProgramBindingBase::CleanupShaders(GLES2Interface* context) {
122  if (vertex_shader_id_) {
123    context->DeleteShader(vertex_shader_id_);
124    vertex_shader_id_ = 0;
125  }
126  if (fragment_shader_id_) {
127    context->DeleteShader(fragment_shader_id_);
128    fragment_shader_id_ = 0;
129  }
130}
131
132}  // namespace cc
133