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_translator.h"
11 #include "base/at_exit.h"
12 #include "base/debug/trace_event.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/strings/string_number_conversions.h"
19 using gpu::gles2::ShaderTranslator
;
21 class ShaderTranslatorInitializer
{
23 ShaderTranslatorInitializer() {
24 TRACE_EVENT0("gpu", "ShInitialize");
25 CHECK(ShInitialize());
28 ~ShaderTranslatorInitializer() {
29 TRACE_EVENT0("gpu", "ShFinalize");
34 base::LazyInstance
<ShaderTranslatorInitializer
> g_translator_initializer
=
35 LAZY_INSTANCE_INITIALIZER
;
37 void GetVariableInfo(ShHandle compiler
, ShShaderInfo var_type
,
38 ShaderTranslator::VariableMap
* var_map
) {
43 size_t name_len
= 0, mapped_name_len
= 0;
45 case SH_ACTIVE_ATTRIBUTES
:
46 ShGetInfo(compiler
, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &name_len
);
48 case SH_ACTIVE_UNIFORMS
:
49 ShGetInfo(compiler
, SH_ACTIVE_UNIFORM_MAX_LENGTH
, &name_len
);
52 ShGetInfo(compiler
, SH_VARYING_MAX_LENGTH
, &name_len
);
54 default: NOTREACHED();
56 ShGetInfo(compiler
, SH_MAPPED_NAME_MAX_LENGTH
, &mapped_name_len
);
57 if (name_len
<= 1 || mapped_name_len
<= 1) return;
58 scoped_ptr
<char[]> name(new char[name_len
]);
59 scoped_ptr
<char[]> mapped_name(new char[mapped_name_len
]);
62 ShGetInfo(compiler
, var_type
, &num_vars
);
63 for (size_t i
= 0; i
< num_vars
; ++i
) {
66 sh::GLenum type
= GL_NONE
;
67 ShPrecisionType precision
= SH_PRECISION_UNDEFINED
;
70 ShGetVariableInfo(compiler
, var_type
, i
,
71 &len
, &size
, &type
, &precision
, &static_use
,
72 name
.get(), mapped_name
.get());
74 // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
75 // to handle long struct field name mapping before we can do this.
76 // Also, we should modify the ANGLE interface to also return a length
78 std::string
name_string(name
.get(), std::min(len
, name_len
- 1));
79 mapped_name
.get()[mapped_name_len
- 1] = '\0';
81 ShaderTranslator::VariableInfo
info(
82 type
, size
, precision
, static_use
, name_string
);
83 (*var_map
)[mapped_name
.get()] = info
;
87 void GetNameHashingInfo(
88 ShHandle compiler
, ShaderTranslator::NameMap
* name_map
) {
93 size_t hashed_names_count
= 0;
94 ShGetInfo(compiler
, SH_HASHED_NAMES_COUNT
, &hashed_names_count
);
95 if (hashed_names_count
== 0)
98 size_t name_max_len
= 0, hashed_name_max_len
= 0;
99 ShGetInfo(compiler
, SH_NAME_MAX_LENGTH
, &name_max_len
);
100 ShGetInfo(compiler
, SH_HASHED_NAME_MAX_LENGTH
, &hashed_name_max_len
);
102 scoped_ptr
<char[]> name(new char[name_max_len
]);
103 scoped_ptr
<char[]> hashed_name(new char[hashed_name_max_len
]);
105 for (size_t i
= 0; i
< hashed_names_count
; ++i
) {
106 ShGetNameHashingEntry(compiler
, i
, name
.get(), hashed_name
.get());
107 (*name_map
)[hashed_name
.get()] = name
.get();
116 ShaderTranslator::DestructionObserver::DestructionObserver() {
119 ShaderTranslator::DestructionObserver::~DestructionObserver() {
122 ShaderTranslator::ShaderTranslator()
124 implementation_is_glsl_es_(false),
125 driver_bug_workarounds_(static_cast<ShCompileOptions
>(0)) {
128 bool ShaderTranslator::Init(
130 ShShaderSpec shader_spec
,
131 const ShBuiltInResources
* resources
,
132 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type
,
133 ShCompileOptions driver_bug_workarounds
) {
134 // Make sure Init is called only once.
135 DCHECK(compiler_
== NULL
);
136 DCHECK(shader_type
== GL_FRAGMENT_SHADER
|| shader_type
== GL_VERTEX_SHADER
);
137 DCHECK(shader_spec
== SH_GLES2_SPEC
|| shader_spec
== SH_WEBGL_SPEC
);
138 DCHECK(resources
!= NULL
);
140 g_translator_initializer
.Get();
142 ShShaderOutput shader_output
=
143 (glsl_implementation_type
== kGlslES
? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT
);
146 TRACE_EVENT0("gpu", "ShConstructCompiler");
147 compiler_
= ShConstructCompiler(
148 shader_type
, shader_spec
, shader_output
, resources
);
150 compiler_options_
= *resources
;
151 implementation_is_glsl_es_
= (glsl_implementation_type
== kGlslES
);
152 driver_bug_workarounds_
= driver_bug_workarounds
;
153 return compiler_
!= NULL
;
156 int ShaderTranslator::GetCompileOptions() const {
157 int compile_options
=
158 SH_OBJECT_CODE
| SH_VARIABLES
| SH_ENFORCE_PACKING_RESTRICTIONS
|
159 SH_LIMIT_EXPRESSION_COMPLEXITY
| SH_LIMIT_CALL_STACK_DEPTH
|
160 SH_CLAMP_INDIRECT_ARRAY_BOUNDS
;
162 compile_options
|= driver_bug_workarounds_
;
164 return compile_options
;
167 bool ShaderTranslator::Translate(const std::string
& shader_source
,
168 std::string
* info_log
,
169 std::string
* translated_source
,
170 VariableMap
* attrib_map
,
171 VariableMap
* uniform_map
,
172 VariableMap
* varying_map
,
173 NameMap
* name_map
) const {
174 // Make sure this instance is initialized.
175 DCHECK(compiler_
!= NULL
);
177 bool success
= false;
179 TRACE_EVENT0("gpu", "ShCompile");
180 const char* const shader_strings
[] = { shader_source
.c_str() };
181 success
= !!ShCompile(
182 compiler_
, shader_strings
, 1, GetCompileOptions());
185 if (translated_source
) {
186 translated_source
->clear();
187 // Get translated shader.
188 size_t obj_code_len
= 0;
189 ShGetInfo(compiler_
, SH_OBJECT_CODE_LENGTH
, &obj_code_len
);
190 if (obj_code_len
> 1) {
191 scoped_ptr
<char[]> buffer(new char[obj_code_len
]);
192 ShGetObjectCode(compiler_
, buffer
.get());
193 *translated_source
= std::string(buffer
.get(), obj_code_len
- 1);
196 // Get info for attribs, uniforms, and varyings.
197 GetVariableInfo(compiler_
, SH_ACTIVE_ATTRIBUTES
, attrib_map
);
198 GetVariableInfo(compiler_
, SH_ACTIVE_UNIFORMS
, uniform_map
);
199 GetVariableInfo(compiler_
, SH_VARYINGS
, varying_map
);
200 // Get info for name hashing.
201 GetNameHashingInfo(compiler_
, name_map
);
207 size_t info_log_len
= 0;
208 ShGetInfo(compiler_
, SH_INFO_LOG_LENGTH
, &info_log_len
);
209 if (info_log_len
> 1) {
210 scoped_ptr
<char[]> buffer(new char[info_log_len
]);
211 ShGetInfoLog(compiler_
, buffer
.get());
212 *info_log
= std::string(buffer
.get(), info_log_len
- 1);
219 std::string
ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation()
221 DCHECK(compiler_
!= NULL
);
223 size_t resource_len
= 0;
224 ShGetInfo(compiler_
, SH_RESOURCES_STRING_LENGTH
, &resource_len
);
225 DCHECK(resource_len
> 1);
226 scoped_ptr
<char[]> resource_str(new char[resource_len
]);
228 ShGetBuiltInResourcesString(compiler_
, resource_len
, resource_str
.get());
230 return std::string(":CompileOptions:" +
231 base::IntToString(GetCompileOptions())) +
232 std::string(resource_str
.get());
235 void ShaderTranslator::AddDestructionObserver(
236 DestructionObserver
* observer
) {
237 destruction_observers_
.AddObserver(observer
);
240 void ShaderTranslator::RemoveDestructionObserver(
241 DestructionObserver
* observer
) {
242 destruction_observers_
.RemoveObserver(observer
);
245 ShaderTranslator::~ShaderTranslator() {
246 FOR_EACH_OBSERVER(DestructionObserver
,
247 destruction_observers_
,
250 if (compiler_
!= NULL
)
251 ShDestruct(compiler_
);