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"
10 #include "base/at_exit.h"
11 #include "base/debug/trace_event.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/strings/string_number_conversions.h"
18 using gpu::gles2::ShaderTranslator
;
20 class ShaderTranslatorInitializer
{
22 ShaderTranslatorInitializer() {
23 TRACE_EVENT0("gpu", "ShInitialize");
24 CHECK(ShInitialize());
27 ~ShaderTranslatorInitializer() {
28 TRACE_EVENT0("gpu", "ShFinalize");
33 base::LazyInstance
<ShaderTranslatorInitializer
> g_translator_initializer
=
34 LAZY_INSTANCE_INITIALIZER
;
36 #if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
37 typedef int ANGLEGetInfoType
;
39 typedef size_t ANGLEGetInfoType
;
42 void GetVariableInfo(ShHandle compiler
, ShShaderInfo var_type
,
43 ShaderTranslator::VariableMap
* var_map
) {
44 ANGLEGetInfoType name_len
= 0, mapped_name_len
= 0;
46 case SH_ACTIVE_ATTRIBUTES
:
47 ShGetInfo(compiler
, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &name_len
);
49 case SH_ACTIVE_UNIFORMS
:
50 ShGetInfo(compiler
, SH_ACTIVE_UNIFORM_MAX_LENGTH
, &name_len
);
53 ShGetInfo(compiler
, SH_VARYING_MAX_LENGTH
, &name_len
);
55 default: NOTREACHED();
57 ShGetInfo(compiler
, SH_MAPPED_NAME_MAX_LENGTH
, &mapped_name_len
);
58 if (name_len
<= 1 || mapped_name_len
<= 1) return;
59 scoped_ptr
<char[]> name(new char[name_len
]);
60 scoped_ptr
<char[]> mapped_name(new char[mapped_name_len
]);
62 ANGLEGetInfoType num_vars
= 0;
63 ShGetInfo(compiler
, var_type
, &num_vars
);
64 for (ANGLEGetInfoType i
= 0; i
< num_vars
; ++i
) {
65 ANGLEGetInfoType len
= 0;
67 ShDataType type
= SH_NONE
;
68 ShPrecisionType precision
= SH_PRECISION_UNDEFINED
;
71 ShGetVariableInfo(compiler
, var_type
, i
,
72 &len
, &size
, &type
, &precision
, &static_use
,
73 name
.get(), mapped_name
.get());
75 // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
76 // to handle long struct field name mapping before we can do this.
77 // Also, we should modify the ANGLE interface to also return a length
79 std::string
name_string(name
.get(), std::min(len
, name_len
- 1));
80 mapped_name
.get()[mapped_name_len
- 1] = '\0';
82 ShaderTranslator::VariableInfo
info(
83 type
, size
, precision
, static_use
, name_string
);
84 (*var_map
)[mapped_name
.get()] = info
;
88 void GetNameHashingInfo(
89 ShHandle compiler
, ShaderTranslator::NameMap
* name_map
) {
90 ANGLEGetInfoType hashed_names_count
= 0;
91 ShGetInfo(compiler
, SH_HASHED_NAMES_COUNT
, &hashed_names_count
);
92 if (hashed_names_count
== 0)
95 ANGLEGetInfoType name_max_len
= 0, hashed_name_max_len
= 0;
96 ShGetInfo(compiler
, SH_NAME_MAX_LENGTH
, &name_max_len
);
97 ShGetInfo(compiler
, SH_HASHED_NAME_MAX_LENGTH
, &hashed_name_max_len
);
99 scoped_ptr
<char[]> name(new char[name_max_len
]);
100 scoped_ptr
<char[]> hashed_name(new char[hashed_name_max_len
]);
102 for (ANGLEGetInfoType i
= 0; i
< hashed_names_count
; ++i
) {
103 ShGetNameHashingEntry(compiler
, i
, name
.get(), hashed_name
.get());
104 (*name_map
)[hashed_name
.get()] = name
.get();
113 ShaderTranslator::DestructionObserver::DestructionObserver() {
116 ShaderTranslator::DestructionObserver::~DestructionObserver() {
119 ShaderTranslator::ShaderTranslator()
121 implementation_is_glsl_es_(false),
122 driver_bug_workarounds_(static_cast<ShCompileOptions
>(0)) {
125 bool ShaderTranslator::Init(
126 ShShaderType shader_type
,
127 ShShaderSpec shader_spec
,
128 const ShBuiltInResources
* resources
,
129 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type
,
130 ShCompileOptions driver_bug_workarounds
) {
131 // Make sure Init is called only once.
132 DCHECK(compiler_
== NULL
);
133 DCHECK(shader_type
== SH_FRAGMENT_SHADER
|| shader_type
== SH_VERTEX_SHADER
);
134 DCHECK(shader_spec
== SH_GLES2_SPEC
|| shader_spec
== SH_WEBGL_SPEC
);
135 DCHECK(resources
!= NULL
);
137 g_translator_initializer
.Get();
139 ShShaderOutput shader_output
=
140 (glsl_implementation_type
== kGlslES
? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT
);
143 TRACE_EVENT0("gpu", "ShConstructCompiler");
144 compiler_
= ShConstructCompiler(
145 shader_type
, shader_spec
, shader_output
, resources
);
147 compiler_options_
= *resources
;
148 implementation_is_glsl_es_
= (glsl_implementation_type
== kGlslES
);
149 driver_bug_workarounds_
= driver_bug_workarounds
;
150 return compiler_
!= NULL
;
153 int ShaderTranslator::GetCompileOptions() const {
154 int compile_options
=
155 SH_OBJECT_CODE
| SH_VARIABLES
| SH_ENFORCE_PACKING_RESTRICTIONS
|
156 SH_LIMIT_EXPRESSION_COMPLEXITY
| SH_LIMIT_CALL_STACK_DEPTH
|
157 SH_CLAMP_INDIRECT_ARRAY_BOUNDS
;
159 compile_options
|= driver_bug_workarounds_
;
161 return compile_options
;
164 bool ShaderTranslator::Translate(const char* shader
) {
165 // Make sure this instance is initialized.
166 DCHECK(compiler_
!= NULL
);
167 DCHECK(shader
!= NULL
);
170 bool success
= false;
172 TRACE_EVENT0("gpu", "ShCompile");
173 success
= !!ShCompile(compiler_
, &shader
, 1, GetCompileOptions());
176 // Get translated shader.
177 ANGLEGetInfoType obj_code_len
= 0;
178 ShGetInfo(compiler_
, SH_OBJECT_CODE_LENGTH
, &obj_code_len
);
179 if (obj_code_len
> 1) {
180 translated_shader_
.reset(new char[obj_code_len
]);
181 ShGetObjectCode(compiler_
, translated_shader_
.get());
183 // Get info for attribs and uniforms.
184 GetVariableInfo(compiler_
, SH_ACTIVE_ATTRIBUTES
, &attrib_map_
);
185 GetVariableInfo(compiler_
, SH_ACTIVE_UNIFORMS
, &uniform_map_
);
186 GetVariableInfo(compiler_
, SH_VARYINGS
, &varying_map_
);
187 // Get info for name hashing.
188 GetNameHashingInfo(compiler_
, &name_map_
);
192 ANGLEGetInfoType info_log_len
= 0;
193 ShGetInfo(compiler_
, SH_INFO_LOG_LENGTH
, &info_log_len
);
194 if (info_log_len
> 1) {
195 info_log_
.reset(new char[info_log_len
]);
196 ShGetInfoLog(compiler_
, info_log_
.get());
204 std::string
ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation()
206 #if ANGLE_SH_VERSION >= 124
207 DCHECK(compiler_
!= NULL
);
209 ANGLEGetInfoType resource_len
= 0;
210 ShGetInfo(compiler_
, SH_RESOURCES_STRING_LENGTH
, &resource_len
);
211 DCHECK(resource_len
> 1);
212 scoped_ptr
<char[]> resource_str(new char[resource_len
]);
214 ShGetBuiltInResourcesString(compiler_
, resource_len
, resource_str
.get());
216 return std::string(":CompileOptions:" +
217 base::IntToString(GetCompileOptions())) +
218 std::string(resource_str
.get());
220 #if ANGLE_SH_VERSION >= 123
221 const size_t kNumIntFields
= 21;
222 #elif ANGLE_SH_VERSION >= 122
223 const size_t kNumIntFields
= 20;
225 const size_t kNumIntFields
= 16;
227 const size_t kNumEnumFields
= 1;
228 const size_t kNumFunctionPointerFields
= 1;
229 struct MustMatchShBuiltInResource
{
230 typedef khronos_uint64_t (*FunctionPointer
)(const char*, size_t);
234 int int_fields
[kNumIntFields
];
235 FunctionPointer pointer_fields
[kNumFunctionPointerFields
];
236 Enum enum_fields
[kNumEnumFields
];
238 // If this assert fails most likely that means something below needs updating.
240 sizeof(ShBuiltInResources
) == sizeof(MustMatchShBuiltInResource
),
241 Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below
);
245 base::IntToString(GetCompileOptions()) +
246 ":MaxVertexAttribs:" +
247 base::IntToString(compiler_options_
.MaxVertexAttribs
) +
248 ":MaxVertexUniformVectors:" +
249 base::IntToString(compiler_options_
.MaxVertexUniformVectors
) +
250 ":MaxVaryingVectors:" +
251 base::IntToString(compiler_options_
.MaxVaryingVectors
) +
252 ":MaxVertexTextureImageUnits:" +
253 base::IntToString(compiler_options_
.MaxVertexTextureImageUnits
) +
254 ":MaxCombinedTextureImageUnits:" +
255 base::IntToString(compiler_options_
.MaxCombinedTextureImageUnits
) +
256 ":MaxTextureImageUnits:" +
257 base::IntToString(compiler_options_
.MaxTextureImageUnits
) +
258 ":MaxFragmentUniformVectors:" +
259 base::IntToString(compiler_options_
.MaxFragmentUniformVectors
) +
261 base::IntToString(compiler_options_
.MaxDrawBuffers
) +
262 ":OES_standard_derivatives:" +
263 base::IntToString(compiler_options_
.OES_standard_derivatives
) +
264 ":OES_EGL_image_external:" +
265 base::IntToString(compiler_options_
.OES_EGL_image_external
) +
266 ":ARB_texture_rectangle:" +
267 base::IntToString(compiler_options_
.ARB_texture_rectangle
) +
268 ":EXT_draw_buffers:" +
269 base::IntToString(compiler_options_
.EXT_draw_buffers
) +
270 ":FragmentPrecisionHigh:" +
271 base::IntToString(compiler_options_
.FragmentPrecisionHigh
) +
272 ":MaxExpressionComplexity:" +
273 base::IntToString(compiler_options_
.MaxExpressionComplexity
) +
274 ":MaxCallStackDepth:" +
275 base::IntToString(compiler_options_
.MaxCallStackDepth
) +
277 #if ANGLE_SH_VERSION >= 122
278 base::IntToString(compiler_options_
.EXT_frag_depth
) +
279 #if ANGLE_SH_VERSION >= 123
280 ":EXT_shader_texture_lod:" +
281 base::IntToString(compiler_options_
.EXT_shader_texture_lod
) +
283 ":MaxVertexOutputVectors:" +
284 base::IntToString(compiler_options_
.MaxVertexOutputVectors
) +
285 ":MaxFragmentInputVectors:" +
286 base::IntToString(compiler_options_
.MaxFragmentInputVectors
) +
287 ":MinProgramTexelOffset:" +
288 base::IntToString(compiler_options_
.MinProgramTexelOffset
) +
289 ":MaxProgramTexelOffset:" +
290 base::IntToString(compiler_options_
.MaxProgramTexelOffset
));
291 #else // ANGLE_SH_VERSION < 122
292 base::IntToString(compiler_options_
.EXT_frag_depth
));
297 const char* ShaderTranslator::translated_shader() const {
298 return translated_shader_
.get();
301 const char* ShaderTranslator::info_log() const {
302 return info_log_
.get();
305 const ShaderTranslatorInterface::VariableMap
&
306 ShaderTranslator::attrib_map() const {
310 const ShaderTranslatorInterface::VariableMap
&
311 ShaderTranslator::uniform_map() const {
315 const ShaderTranslatorInterface::VariableMap
&
316 ShaderTranslator::varying_map() const {
320 const ShaderTranslatorInterface::NameMap
&
321 ShaderTranslator::name_map() const {
325 void ShaderTranslator::AddDestructionObserver(
326 DestructionObserver
* observer
) {
327 destruction_observers_
.AddObserver(observer
);
330 void ShaderTranslator::RemoveDestructionObserver(
331 DestructionObserver
* observer
) {
332 destruction_observers_
.RemoveObserver(observer
);
335 ShaderTranslator::~ShaderTranslator() {
336 FOR_EACH_OBSERVER(DestructionObserver
,
337 destruction_observers_
,
340 if (compiler_
!= NULL
)
341 ShDestruct(compiler_
);
344 void ShaderTranslator::ClearResults() {
345 translated_shader_
.reset();
348 uniform_map_
.clear();
349 varying_map_
.clear();