Home | History | Annotate | Download | only in output
      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 "cc/output/gl_renderer.h"  // For the GLC() macro.
     10 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
     11 #include "third_party/khronos/GLES2/gl2.h"
     12 
     13 using WebKit::WebGraphicsContext3D;
     14 
     15 namespace cc {
     16 
     17 ProgramBindingBase::ProgramBindingBase()
     18     : program_(0),
     19       vertex_shader_id_(0),
     20       fragment_shader_id_(0),
     21       initialized_(false) {}
     22 
     23 ProgramBindingBase::~ProgramBindingBase() {
     24   // If you hit these asserts, you initialized but forgot to call Cleanup().
     25   DCHECK(!program_);
     26   DCHECK(!vertex_shader_id_);
     27   DCHECK(!fragment_shader_id_);
     28   DCHECK(!initialized_);
     29 }
     30 
     31 void ProgramBindingBase::Init(WebGraphicsContext3D* context,
     32                               const std::string& vertex_shader,
     33                               const std::string& fragment_shader) {
     34   TRACE_EVENT0("cc", "ProgramBindingBase::init");
     35   vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
     36   if (!vertex_shader_id_) {
     37     if (!IsContextLost(context))
     38       LOG(ERROR) << "Failed to create vertex shader";
     39     return;
     40   }
     41 
     42   fragment_shader_id_ =
     43       LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
     44   if (!fragment_shader_id_) {
     45     GLC(context, context->deleteShader(vertex_shader_id_));
     46     vertex_shader_id_ = 0;
     47     if (!IsContextLost(context))
     48       LOG(ERROR) << "Failed to create fragment shader";
     49     return;
     50   }
     51 
     52   program_ =
     53       CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
     54   DCHECK(program_ || IsContextLost(context));
     55 }
     56 
     57 void ProgramBindingBase::Link(WebGraphicsContext3D* context) {
     58   GLC(context, context->linkProgram(program_));
     59   CleanupShaders(context);
     60   if (!program_)
     61     return;
     62 #ifndef NDEBUG
     63   int linked = 0;
     64   GLC(context, context->getProgramiv(program_, GL_LINK_STATUS, &linked));
     65   if (!linked) {
     66     if (!IsContextLost(context))
     67       LOG(ERROR) << "Failed to link shader program";
     68     GLC(context, context->deleteProgram(program_));
     69   }
     70 #endif
     71 }
     72 
     73 void ProgramBindingBase::Cleanup(WebGraphicsContext3D* context) {
     74   initialized_ = false;
     75   if (!program_)
     76     return;
     77 
     78   DCHECK(context);
     79   GLC(context, context->deleteProgram(program_));
     80   program_ = 0;
     81 
     82   CleanupShaders(context);
     83 }
     84 
     85 unsigned ProgramBindingBase::LoadShader(WebGraphicsContext3D* context,
     86                                         unsigned type,
     87                                         const std::string& shader_source) {
     88   unsigned shader = context->createShader(type);
     89   if (!shader)
     90     return 0;
     91   GLC(context, context->shaderSource(shader, shader_source.data()));
     92   GLC(context, context->compileShader(shader));
     93 #ifndef NDEBUG
     94   int compiled = 0;
     95   GLC(context, context->getShaderiv(shader, GL_COMPILE_STATUS, &compiled));
     96   if (!compiled) {
     97     GLC(context, context->deleteShader(shader));
     98     return 0;
     99   }
    100 #endif
    101   return shader;
    102 }
    103 
    104 unsigned ProgramBindingBase::CreateShaderProgram(WebGraphicsContext3D* context,
    105                                                  unsigned vertex_shader,
    106                                                  unsigned fragment_shader) {
    107   unsigned program_object = context->createProgram();
    108   if (!program_object) {
    109     if (!IsContextLost(context))
    110       LOG(ERROR) << "Failed to create shader program";
    111     return 0;
    112   }
    113 
    114   GLC(context, context->attachShader(program_object, vertex_shader));
    115   GLC(context, context->attachShader(program_object, fragment_shader));
    116 
    117   // Bind the common attrib locations.
    118   GLC(context,
    119       context->bindAttribLocation(program_object,
    120                                   GeometryBinding::PositionAttribLocation(),
    121                                   "a_position"));
    122   GLC(context,
    123       context->bindAttribLocation(program_object,
    124                                   GeometryBinding::TexCoordAttribLocation(),
    125                                   "a_texCoord"));
    126   GLC(context,
    127       context->bindAttribLocation(
    128           program_object,
    129           GeometryBinding::TriangleIndexAttribLocation(),
    130           "a_index"));
    131 
    132   return program_object;
    133 }
    134 
    135 void ProgramBindingBase::CleanupShaders(WebGraphicsContext3D* context) {
    136   if (vertex_shader_id_) {
    137     GLC(context, context->deleteShader(vertex_shader_id_));
    138     vertex_shader_id_ = 0;
    139   }
    140   if (fragment_shader_id_) {
    141     GLC(context, context->deleteShader(fragment_shader_id_));
    142     fragment_shader_id_ = 0;
    143   }
    144 }
    145 
    146 bool ProgramBindingBase::IsContextLost(WebGraphicsContext3D* context) {
    147   return (context->getGraphicsResetStatusARB() != GL_NO_ERROR);
    148 }
    149 
    150 }  // namespace cc
    151