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.
5 #include "gpu/command_buffer/service/shader_manager.h"
9 #include "base/logging.h"
10 #include "base/strings/string_util.h"
17 // Given a variable name | a[0].b.c[0] |, return |a|.
18 std::string
GetTopVariableName(const std::string
& fullname
) {
19 size_t pos
= fullname
.find_first_of("[.");
20 if (pos
== std::string::npos
)
22 return fullname
.substr(0, pos
);
25 } // namespace anonymous
27 Shader::Shader(GLuint service_id
, GLenum shader_type
)
29 shader_state_(kShaderStateWaiting
),
30 marked_for_deletion_(false),
31 service_id_(service_id
),
32 shader_type_(shader_type
),
33 shader_version_(kUndefinedShaderVersion
),
41 void Shader::Destroy() {
47 void Shader::RequestCompile(scoped_refptr
<ShaderTranslatorInterface
> translator
,
48 TranslatedShaderSourceType type
) {
49 shader_state_
= kShaderStateCompileRequested
;
50 translator_
= translator
;
52 last_compiled_source_
= source_
;
55 void Shader::DoCompile() {
56 // We require that RequestCompile() must be called before DoCompile(),
57 // so we can return early if the shader state is not what we expect.
58 if (shader_state_
!= kShaderStateCompileRequested
) {
62 // Signify the shader has been compiled, whether or not it is valid
63 // is dependent on the |valid_| member variable.
64 shader_state_
= kShaderStateCompiled
;
67 // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
68 // glShaderSource and then glCompileShader.
69 const char* source_for_driver
= last_compiled_source_
.c_str();
70 ShaderTranslatorInterface
* translator
= translator_
.get();
72 bool success
= translator
->Translate(last_compiled_source_
,
83 source_for_driver
= translated_source_
.c_str();
86 glShaderSource(service_id_
, 1, &source_for_driver
, NULL
);
87 glCompileShader(service_id_
);
88 if (source_type_
== kANGLE
) {
90 glGetShaderiv(service_id_
,
91 GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE
,
93 source_for_driver
= "\0";
94 translated_source_
.resize(max_len
);
97 glGetTranslatedShaderSourceANGLE(
98 service_id_
, translated_source_
.size(),
99 &len
, &translated_source_
.at(0));
100 DCHECK(max_len
== 0 || len
< max_len
);
101 DCHECK(len
== 0 || translated_source_
[len
] == '\0');
102 translated_source_
.resize(len
);
103 source_for_driver
= translated_source_
.c_str();
107 GLint status
= GL_FALSE
;
108 glGetShaderiv(service_id_
, GL_COMPILE_STATUS
, &status
);
109 if (status
== GL_TRUE
) {
114 // We cannot reach here if we are using the shader translator.
115 // All invalid shaders must be rejected by the translator.
116 // All translated shaders must compile.
117 std::string translator_log
= log_info_
;
120 glGetShaderiv(service_id_
, GL_INFO_LOG_LENGTH
, &max_len
);
121 log_info_
.resize(max_len
);
124 glGetShaderInfoLog(service_id_
, log_info_
.size(), &len
, &log_info_
.at(0));
125 DCHECK(max_len
== 0 || len
< max_len
);
126 DCHECK(len
== 0 || log_info_
[len
] == '\0');
127 log_info_
.resize(len
);
130 LOG_IF(ERROR
, translator
)
131 << "Shader translator allowed/produced an invalid shader "
132 << "unless the driver is buggy:"
133 << "\n--Log from shader translator--\n" << translator_log
134 << "\n--original-shader--\n" << last_compiled_source_
135 << "\n--translated-shader--\n" << source_for_driver
136 << "\n--info-log--\n" << log_info_
;
140 void Shader::IncUseCount() {
144 void Shader::DecUseCount() {
146 DCHECK_GE(use_count_
, 0);
147 if (service_id_
&& use_count_
== 0 && marked_for_deletion_
) {
152 void Shader::MarkForDeletion() {
153 DCHECK(!marked_for_deletion_
);
154 DCHECK_NE(service_id_
, 0u);
156 marked_for_deletion_
= true;
157 if (use_count_
== 0) {
162 void Shader::DeleteServiceID() {
163 DCHECK_NE(service_id_
, 0u);
164 glDeleteShader(service_id_
);
168 const sh::Attribute
* Shader::GetAttribInfo(const std::string
& name
) const {
169 // Vertex attributes can't be arrays or structs (GLSL ES 3.00.4, section
170 // 4.3.4, "Input Variables"), so |name| is the top level name used as
171 // the AttributeMap key.
172 AttributeMap::const_iterator it
= attrib_map_
.find(name
);
173 return it
!= attrib_map_
.end() ? &it
->second
: NULL
;
176 const std::string
* Shader::GetAttribMappedName(
177 const std::string
& original_name
) const {
178 for (AttributeMap::const_iterator it
= attrib_map_
.begin();
179 it
!= attrib_map_
.end(); ++it
) {
180 if (it
->second
.name
== original_name
)
186 const std::string
* Shader::GetOriginalNameFromHashedName(
187 const std::string
& hashed_name
) const {
188 NameMap::const_iterator it
= name_map_
.find(hashed_name
);
189 if (it
!= name_map_
.end())
190 return &(it
->second
);
194 const sh::Uniform
* Shader::GetUniformInfo(const std::string
& name
) const {
195 UniformMap::const_iterator it
= uniform_map_
.find(GetTopVariableName(name
));
196 return it
!= uniform_map_
.end() ? &it
->second
: NULL
;
199 const sh::Varying
* Shader::GetVaryingInfo(const std::string
& name
) const {
200 VaryingMap::const_iterator it
= varying_map_
.find(GetTopVariableName(name
));
201 return it
!= varying_map_
.end() ? &it
->second
: NULL
;
204 ShaderManager::ShaderManager() {}
206 ShaderManager::~ShaderManager() {
207 DCHECK(shaders_
.empty());
210 void ShaderManager::Destroy(bool have_context
) {
211 while (!shaders_
.empty()) {
213 Shader
* shader
= shaders_
.begin()->second
.get();
216 shaders_
.erase(shaders_
.begin());
220 Shader
* ShaderManager::CreateShader(
223 GLenum shader_type
) {
224 std::pair
<ShaderMap::iterator
, bool> result
=
225 shaders_
.insert(std::make_pair(
226 client_id
, scoped_refptr
<Shader
>(
227 new Shader(service_id
, shader_type
))));
228 DCHECK(result
.second
);
229 return result
.first
->second
.get();
232 Shader
* ShaderManager::GetShader(GLuint client_id
) {
233 ShaderMap::iterator it
= shaders_
.find(client_id
);
234 return it
!= shaders_
.end() ? it
->second
.get() : NULL
;
237 bool ShaderManager::GetClientId(GLuint service_id
, GLuint
* client_id
) const {
238 // This doesn't need to be fast. It's only used during slow queries.
239 for (ShaderMap::const_iterator it
= shaders_
.begin();
240 it
!= shaders_
.end(); ++it
) {
241 if (it
->second
->service_id() == service_id
) {
242 *client_id
= it
->first
;
249 bool ShaderManager::IsOwned(Shader
* shader
) {
250 for (ShaderMap::iterator it
= shaders_
.begin();
251 it
!= shaders_
.end(); ++it
) {
252 if (it
->second
.get() == shader
) {
259 void ShaderManager::RemoveShader(Shader
* shader
) {
261 DCHECK(IsOwned(shader
));
262 if (shader
->IsDeleted() && !shader
->InUse()) {
263 for (ShaderMap::iterator it
= shaders_
.begin();
264 it
!= shaders_
.end(); ++it
) {
265 if (it
->second
.get() == shader
) {
274 void ShaderManager::Delete(Shader
* shader
) {
276 DCHECK(IsOwned(shader
));
277 shader
->MarkForDeletion();
278 RemoveShader(shader
);
281 void ShaderManager::UseShader(Shader
* shader
) {
283 DCHECK(IsOwned(shader
));
284 shader
->IncUseCount();
287 void ShaderManager::UnuseShader(Shader
* shader
) {
289 DCHECK(IsOwned(shader
));
290 shader
->DecUseCount();
291 RemoveShader(shader
);