12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2011 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/output/program_binding.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/trace_event.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "cc/output/geometry_binding.h"
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "gpu/command_buffer/client/gles2_interface.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using gpu::gles2::GLES2Interface;
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace cc {
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProgramBindingBase::ProgramBindingBase()
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : program_(0),
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      vertex_shader_id_(0),
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      fragment_shader_id_(0),
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initialized_(false) {}
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ProgramBindingBase::~ProgramBindingBase() {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If you hit these asserts, you initialized but forgot to call Cleanup().
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!program_);
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!vertex_shader_id_);
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!fragment_shader_id_);
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!initialized_);
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ProgramBindingBase::Init(GLES2Interface* context,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const std::string& vertex_shader,
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const std::string& fragment_shader) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TRACE_EVENT0("cc", "ProgramBindingBase::init");
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!vertex_shader_id_)
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fragment_shader_id_ =
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!fragment_shader_id_) {
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    context->DeleteShader(vertex_shader_id_);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    vertex_shader_id_ = 0;
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  program_ =
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return !!program_;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool ProgramBindingBase::Link(GLES2Interface* context) {
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->LinkProgram(program_);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CleanupShaders(context);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!program_)
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef NDEBUG
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int linked = 0;
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!linked)
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return true;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ProgramBindingBase::Cleanup(GLES2Interface* context) {
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  initialized_ = false;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!program_)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(context);
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->DeleteProgram(program_);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  program_ = 0;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CleanupShaders(context);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)unsigned ProgramBindingBase::LoadShader(GLES2Interface* context,
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        unsigned type,
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                        const std::string& shader_source) {
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  unsigned shader = context->CreateShader(type);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!shader)
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return 0u;
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  const char* shader_source_str[] = { shader_source.data() };
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int shader_length[] = { static_cast<int>(shader_source.length()) };
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->ShaderSource(
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      shader, 1,
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      shader_source_str,
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      shader_length);
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->CompileShader(shader);
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef NDEBUG
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int compiled = 0;
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!compiled)
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return 0u;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return shader;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context,
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 unsigned vertex_shader,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 unsigned fragment_shader) {
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  unsigned program_object = context->CreateProgram();
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!program_object)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->AttachShader(program_object, vertex_shader);
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->AttachShader(program_object, fragment_shader);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Bind the common attrib locations.
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->BindAttribLocation(
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      program_object, GeometryBinding::PositionAttribLocation(), "a_position");
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->BindAttribLocation(
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord");
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  context->BindAttribLocation(program_object,
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              GeometryBinding::TriangleIndexAttribLocation(),
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              "a_index");
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return program_object;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ProgramBindingBase::CleanupShaders(GLES2Interface* context) {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (vertex_shader_id_) {
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    context->DeleteShader(vertex_shader_id_);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    vertex_shader_id_ = 0;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (fragment_shader_id_) {
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    context->DeleteShader(fragment_shader_id_);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    fragment_shader_id_ = 0;
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace cc
133