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