1// Copyright (c) 2012 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 "gpu/command_buffer/service/shader_manager.h"
6
7#include <utility>
8
9#include "base/logging.h"
10#include "base/strings/string_util.h"
11
12namespace gpu {
13namespace gles2 {
14
15Shader::Shader(GLuint service_id, GLenum shader_type)
16      : use_count_(0),
17        service_id_(service_id),
18        shader_type_(shader_type),
19        valid_(false) {
20}
21
22Shader::~Shader() {
23}
24
25void Shader::DoCompile(ShaderTranslatorInterface* translator,
26                       TranslatedShaderSourceType type) {
27  // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
28  // glShaderSource and then glCompileShader.
29  const char* source_for_driver = source_.c_str();
30  if (translator) {
31    valid_ = translator->Translate(source_,
32                                   &log_info_,
33                                   &translated_source_,
34                                   &attrib_map_,
35                                   &uniform_map_,
36                                   &varying_map_,
37                                   &name_map_);
38    if (!valid_) {
39      return;
40    }
41    signature_source_ = source_;
42    source_for_driver = translated_source_.c_str();
43  }
44
45  glShaderSource(service_id_, 1, &source_for_driver, NULL);
46  glCompileShader(service_id_);
47  if (type == kANGLE) {
48    GLint max_len = 0;
49    glGetShaderiv(service_id_,
50                  GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
51                  &max_len);
52    scoped_ptr<char[]> buffer(new char[max_len]);
53    GLint len = 0;
54    glGetTranslatedShaderSourceANGLE(
55        service_id_, max_len, &len, buffer.get());
56    DCHECK(max_len == 0 || len < max_len);
57    DCHECK(len == 0 || buffer[len] == '\0');
58    translated_source_ = std::string(buffer.get(), len);
59  }
60
61  GLint status = GL_FALSE;
62  glGetShaderiv(service_id_, GL_COMPILE_STATUS, &status);
63  if (status != GL_TRUE) {
64    // We cannot reach here if we are using the shader translator.
65    // All invalid shaders must be rejected by the translator.
66    // All translated shaders must compile.
67    GLint max_len = 0;
68    glGetShaderiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
69    scoped_ptr<char[]> buffer(new char[max_len]);
70    GLint len = 0;
71    glGetShaderInfoLog(service_id_, max_len, &len, buffer.get());
72    DCHECK(max_len == 0 || len < max_len);
73    DCHECK(len == 0 || buffer[len] == '\0');
74    valid_ = false;
75    log_info_ = std::string(buffer.get(), len);
76    LOG_IF(ERROR, translator)
77        << "Shader translator allowed/produced an invalid shader "
78        << "unless the driver is buggy:"
79        << "\n--original-shader--\n" << source_
80        << "\n--translated-shader--\n" << source_for_driver
81        << "\n--info-log--\n" << log_info_;
82  }
83}
84
85void Shader::IncUseCount() {
86  ++use_count_;
87}
88
89void Shader::DecUseCount() {
90  --use_count_;
91  DCHECK_GE(use_count_, 0);
92}
93
94void Shader::MarkAsDeleted() {
95  DCHECK_NE(service_id_, 0u);
96  service_id_ = 0;
97}
98
99const Shader::VariableInfo* Shader::GetAttribInfo(
100    const std::string& name) const {
101  VariableMap::const_iterator it = attrib_map_.find(name);
102  return it != attrib_map_.end() ? &it->second : NULL;
103}
104
105const std::string* Shader::GetAttribMappedName(
106    const std::string& original_name) const {
107  for (VariableMap::const_iterator it = attrib_map_.begin();
108       it != attrib_map_.end(); ++it) {
109    if (it->second.name == original_name)
110      return &(it->first);
111  }
112  return NULL;
113}
114
115const std::string* Shader::GetOriginalNameFromHashedName(
116    const std::string& hashed_name) const {
117  NameMap::const_iterator it = name_map_.find(hashed_name);
118  if (it != name_map_.end())
119    return &(it->second);
120  return NULL;
121}
122
123const Shader::VariableInfo* Shader::GetUniformInfo(
124    const std::string& name) const {
125  VariableMap::const_iterator it = uniform_map_.find(name);
126  return it != uniform_map_.end() ? &it->second : NULL;
127}
128
129const Shader::VariableInfo* Shader::GetVaryingInfo(
130    const std::string& name) const {
131  VariableMap::const_iterator it = varying_map_.find(name);
132  return it != varying_map_.end() ? &it->second : NULL;
133}
134
135ShaderManager::ShaderManager() {}
136
137ShaderManager::~ShaderManager() {
138  DCHECK(shaders_.empty());
139}
140
141void ShaderManager::Destroy(bool have_context) {
142  while (!shaders_.empty()) {
143    if (have_context) {
144      Shader* shader = shaders_.begin()->second.get();
145      if (!shader->IsDeleted()) {
146        glDeleteShader(shader->service_id());
147        shader->MarkAsDeleted();
148      }
149    }
150    shaders_.erase(shaders_.begin());
151  }
152}
153
154Shader* ShaderManager::CreateShader(
155    GLuint client_id,
156    GLuint service_id,
157    GLenum shader_type) {
158  std::pair<ShaderMap::iterator, bool> result =
159      shaders_.insert(std::make_pair(
160          client_id, scoped_refptr<Shader>(
161              new Shader(service_id, shader_type))));
162  DCHECK(result.second);
163  return result.first->second.get();
164}
165
166Shader* ShaderManager::GetShader(GLuint client_id) {
167  ShaderMap::iterator it = shaders_.find(client_id);
168  return it != shaders_.end() ? it->second.get() : NULL;
169}
170
171bool ShaderManager::GetClientId(GLuint service_id, GLuint* client_id) const {
172  // This doesn't need to be fast. It's only used during slow queries.
173  for (ShaderMap::const_iterator it = shaders_.begin();
174       it != shaders_.end(); ++it) {
175    if (it->second->service_id() == service_id) {
176      *client_id = it->first;
177      return true;
178    }
179  }
180  return false;
181}
182
183bool ShaderManager::IsOwned(Shader* shader) {
184  for (ShaderMap::iterator it = shaders_.begin();
185       it != shaders_.end(); ++it) {
186    if (it->second.get() == shader) {
187      return true;
188    }
189  }
190  return false;
191}
192
193void ShaderManager::RemoveShader(Shader* shader) {
194  DCHECK(shader);
195  DCHECK(IsOwned(shader));
196  if (shader->IsDeleted() && !shader->InUse()) {
197    for (ShaderMap::iterator it = shaders_.begin();
198         it != shaders_.end(); ++it) {
199      if (it->second.get() == shader) {
200        shaders_.erase(it);
201        return;
202      }
203    }
204    NOTREACHED();
205  }
206}
207
208void ShaderManager::MarkAsDeleted(Shader* shader) {
209  DCHECK(shader);
210  DCHECK(IsOwned(shader));
211  shader->MarkAsDeleted();
212  RemoveShader(shader);
213}
214
215void ShaderManager::UseShader(Shader* shader) {
216  DCHECK(shader);
217  DCHECK(IsOwned(shader));
218  shader->IncUseCount();
219}
220
221void ShaderManager::UnuseShader(Shader* shader) {
222  DCHECK(shader);
223  DCHECK(IsOwned(shader));
224  shader->DecUseCount();
225  RemoveShader(shader);
226}
227
228}  // namespace gles2
229}  // namespace gpu
230
231
232