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 #if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
38 typedef int ANGLEGetInfoType
;
40 typedef size_t ANGLEGetInfoType
;
43 void GetVariableInfo(ShHandle compiler
, ShShaderInfo var_type
,
44 ShaderTranslator::VariableMap
* var_map
) {
45 ANGLEGetInfoType name_len
= 0, mapped_name_len
= 0;
47 case SH_ACTIVE_ATTRIBUTES
:
48 ShGetInfo(compiler
, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &name_len
);
50 case SH_ACTIVE_UNIFORMS
:
51 ShGetInfo(compiler
, SH_ACTIVE_UNIFORM_MAX_LENGTH
, &name_len
);
54 ShGetInfo(compiler
, SH_VARYING_MAX_LENGTH
, &name_len
);
56 default: NOTREACHED();
58 ShGetInfo(compiler
, SH_MAPPED_NAME_MAX_LENGTH
, &mapped_name_len
);
59 if (name_len
<= 1 || mapped_name_len
<= 1) return;
60 scoped_ptr
<char[]> name(new char[name_len
]);
61 scoped_ptr
<char[]> mapped_name(new char[mapped_name_len
]);
63 ANGLEGetInfoType num_vars
= 0;
64 ShGetInfo(compiler
, var_type
, &num_vars
);
65 for (ANGLEGetInfoType i
= 0; i
< num_vars
; ++i
) {
66 ANGLEGetInfoType len
= 0;
68 #if (ANGLE_SH_VERSION >= 126)
69 sh::GLenum type
= GL_NONE
;
71 ShDataType type
= SH_NONE
;
73 ShPrecisionType precision
= SH_PRECISION_UNDEFINED
;
76 ShGetVariableInfo(compiler
, var_type
, i
,
77 &len
, &size
, &type
, &precision
, &static_use
,
78 name
.get(), mapped_name
.get());
80 // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
81 // to handle long struct field name mapping before we can do this.
82 // Also, we should modify the ANGLE interface to also return a length
84 std::string
name_string(name
.get(), std::min(len
, name_len
- 1));
85 mapped_name
.get()[mapped_name_len
- 1] = '\0';
87 ShaderTranslator::VariableInfo
info(
88 type
, size
, precision
, static_use
, name_string
);
89 (*var_map
)[mapped_name
.get()] = info
;
93 void GetNameHashingInfo(
94 ShHandle compiler
, ShaderTranslator::NameMap
* name_map
) {
95 ANGLEGetInfoType hashed_names_count
= 0;
96 ShGetInfo(compiler
, SH_HASHED_NAMES_COUNT
, &hashed_names_count
);
97 if (hashed_names_count
== 0)
100 ANGLEGetInfoType name_max_len
= 0, hashed_name_max_len
= 0;
101 ShGetInfo(compiler
, SH_NAME_MAX_LENGTH
, &name_max_len
);
102 ShGetInfo(compiler
, SH_HASHED_NAME_MAX_LENGTH
, &hashed_name_max_len
);
104 scoped_ptr
<char[]> name(new char[name_max_len
]);
105 scoped_ptr
<char[]> hashed_name(new char[hashed_name_max_len
]);
107 for (ANGLEGetInfoType i
= 0; i
< hashed_names_count
; ++i
) {
108 ShGetNameHashingEntry(compiler
, i
, name
.get(), hashed_name
.get());
109 (*name_map
)[hashed_name
.get()] = name
.get();
118 ShaderTranslator::DestructionObserver::DestructionObserver() {
121 ShaderTranslator::DestructionObserver::~DestructionObserver() {
124 ShaderTranslator::ShaderTranslator()
126 implementation_is_glsl_es_(false),
127 driver_bug_workarounds_(static_cast<ShCompileOptions
>(0)) {
130 bool ShaderTranslator::Init(
131 #if (ANGLE_SH_VERSION >= 126)
134 ShShaderType shader_type
,
136 ShShaderSpec shader_spec
,
137 const ShBuiltInResources
* resources
,
138 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type
,
139 ShCompileOptions driver_bug_workarounds
) {
140 // Make sure Init is called only once.
141 DCHECK(compiler_
== NULL
);
142 #if (ANGLE_SH_VERSION >= 126)
143 DCHECK(shader_type
== GL_FRAGMENT_SHADER
|| shader_type
== GL_VERTEX_SHADER
);
145 DCHECK(shader_type
== SH_FRAGMENT_SHADER
|| shader_type
== SH_VERTEX_SHADER
);
147 DCHECK(shader_spec
== SH_GLES2_SPEC
|| shader_spec
== SH_WEBGL_SPEC
);
148 DCHECK(resources
!= NULL
);
150 g_translator_initializer
.Get();
152 ShShaderOutput shader_output
=
153 (glsl_implementation_type
== kGlslES
? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT
);
156 TRACE_EVENT0("gpu", "ShConstructCompiler");
157 compiler_
= ShConstructCompiler(
158 shader_type
, shader_spec
, shader_output
, resources
);
160 compiler_options_
= *resources
;
161 implementation_is_glsl_es_
= (glsl_implementation_type
== kGlslES
);
162 driver_bug_workarounds_
= driver_bug_workarounds
;
163 return compiler_
!= NULL
;
166 int ShaderTranslator::GetCompileOptions() const {
167 int compile_options
=
168 SH_OBJECT_CODE
| SH_VARIABLES
| SH_ENFORCE_PACKING_RESTRICTIONS
|
169 SH_LIMIT_EXPRESSION_COMPLEXITY
| SH_LIMIT_CALL_STACK_DEPTH
|
170 SH_CLAMP_INDIRECT_ARRAY_BOUNDS
;
172 compile_options
|= driver_bug_workarounds_
;
174 return compile_options
;
177 bool ShaderTranslator::Translate(const char* shader
) {
178 // Make sure this instance is initialized.
179 DCHECK(compiler_
!= NULL
);
180 DCHECK(shader
!= NULL
);
183 bool success
= false;
185 TRACE_EVENT0("gpu", "ShCompile");
186 success
= !!ShCompile(compiler_
, &shader
, 1, GetCompileOptions());
189 // Get translated shader.
190 ANGLEGetInfoType obj_code_len
= 0;
191 ShGetInfo(compiler_
, SH_OBJECT_CODE_LENGTH
, &obj_code_len
);
192 if (obj_code_len
> 1) {
193 translated_shader_
.reset(new char[obj_code_len
]);
194 ShGetObjectCode(compiler_
, translated_shader_
.get());
196 // Get info for attribs and uniforms.
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_
);
205 ANGLEGetInfoType info_log_len
= 0;
206 ShGetInfo(compiler_
, SH_INFO_LOG_LENGTH
, &info_log_len
);
207 if (info_log_len
> 1) {
208 info_log_
.reset(new char[info_log_len
]);
209 ShGetInfoLog(compiler_
, info_log_
.get());
217 std::string
ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation()
219 #if ANGLE_SH_VERSION >= 124
220 DCHECK(compiler_
!= NULL
);
222 ANGLEGetInfoType resource_len
= 0;
223 ShGetInfo(compiler_
, SH_RESOURCES_STRING_LENGTH
, &resource_len
);
224 DCHECK(resource_len
> 1);
225 scoped_ptr
<char[]> resource_str(new char[resource_len
]);
227 ShGetBuiltInResourcesString(compiler_
, resource_len
, resource_str
.get());
229 return std::string(":CompileOptions:" +
230 base::IntToString(GetCompileOptions())) +
231 std::string(resource_str
.get());
233 #if ANGLE_SH_VERSION >= 123
234 const size_t kNumIntFields
= 21;
235 #elif ANGLE_SH_VERSION >= 122
236 const size_t kNumIntFields
= 20;
238 const size_t kNumIntFields
= 16;
240 const size_t kNumEnumFields
= 1;
241 const size_t kNumFunctionPointerFields
= 1;
242 struct MustMatchShBuiltInResource
{
243 typedef khronos_uint64_t (*FunctionPointer
)(const char*, size_t);
247 int int_fields
[kNumIntFields
];
248 FunctionPointer pointer_fields
[kNumFunctionPointerFields
];
249 Enum enum_fields
[kNumEnumFields
];
251 // If this assert fails most likely that means something below needs updating.
253 sizeof(ShBuiltInResources
) == sizeof(MustMatchShBuiltInResource
),
254 Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below
);
258 base::IntToString(GetCompileOptions()) +
259 ":MaxVertexAttribs:" +
260 base::IntToString(compiler_options_
.MaxVertexAttribs
) +
261 ":MaxVertexUniformVectors:" +
262 base::IntToString(compiler_options_
.MaxVertexUniformVectors
) +
263 ":MaxVaryingVectors:" +
264 base::IntToString(compiler_options_
.MaxVaryingVectors
) +
265 ":MaxVertexTextureImageUnits:" +
266 base::IntToString(compiler_options_
.MaxVertexTextureImageUnits
) +
267 ":MaxCombinedTextureImageUnits:" +
268 base::IntToString(compiler_options_
.MaxCombinedTextureImageUnits
) +
269 ":MaxTextureImageUnits:" +
270 base::IntToString(compiler_options_
.MaxTextureImageUnits
) +
271 ":MaxFragmentUniformVectors:" +
272 base::IntToString(compiler_options_
.MaxFragmentUniformVectors
) +
274 base::IntToString(compiler_options_
.MaxDrawBuffers
) +
275 ":OES_standard_derivatives:" +
276 base::IntToString(compiler_options_
.OES_standard_derivatives
) +
277 ":OES_EGL_image_external:" +
278 base::IntToString(compiler_options_
.OES_EGL_image_external
) +
279 ":ARB_texture_rectangle:" +
280 base::IntToString(compiler_options_
.ARB_texture_rectangle
) +
281 ":EXT_draw_buffers:" +
282 base::IntToString(compiler_options_
.EXT_draw_buffers
) +
283 ":FragmentPrecisionHigh:" +
284 base::IntToString(compiler_options_
.FragmentPrecisionHigh
) +
285 ":MaxExpressionComplexity:" +
286 base::IntToString(compiler_options_
.MaxExpressionComplexity
) +
287 ":MaxCallStackDepth:" +
288 base::IntToString(compiler_options_
.MaxCallStackDepth
) +
290 #if ANGLE_SH_VERSION >= 122
291 base::IntToString(compiler_options_
.EXT_frag_depth
) +
292 #if ANGLE_SH_VERSION >= 123
293 ":EXT_shader_texture_lod:" +
294 base::IntToString(compiler_options_
.EXT_shader_texture_lod
) +
296 ":MaxVertexOutputVectors:" +
297 base::IntToString(compiler_options_
.MaxVertexOutputVectors
) +
298 ":MaxFragmentInputVectors:" +
299 base::IntToString(compiler_options_
.MaxFragmentInputVectors
) +
300 ":MinProgramTexelOffset:" +
301 base::IntToString(compiler_options_
.MinProgramTexelOffset
) +
302 ":MaxProgramTexelOffset:" +
303 base::IntToString(compiler_options_
.MaxProgramTexelOffset
));
304 #else // ANGLE_SH_VERSION < 122
305 base::IntToString(compiler_options_
.EXT_frag_depth
));
310 const char* ShaderTranslator::translated_shader() const {
311 return translated_shader_
.get();
314 const char* ShaderTranslator::info_log() const {
315 return info_log_
.get();
318 const ShaderTranslatorInterface::VariableMap
&
319 ShaderTranslator::attrib_map() const {
323 const ShaderTranslatorInterface::VariableMap
&
324 ShaderTranslator::uniform_map() const {
328 const ShaderTranslatorInterface::VariableMap
&
329 ShaderTranslator::varying_map() const {
333 const ShaderTranslatorInterface::NameMap
&
334 ShaderTranslator::name_map() const {
338 void ShaderTranslator::AddDestructionObserver(
339 DestructionObserver
* observer
) {
340 destruction_observers_
.AddObserver(observer
);
343 void ShaderTranslator::RemoveDestructionObserver(
344 DestructionObserver
* observer
) {
345 destruction_observers_
.RemoveObserver(observer
);
348 ShaderTranslator::~ShaderTranslator() {
349 FOR_EACH_OBSERVER(DestructionObserver
,
350 destruction_observers_
,
353 if (compiler_
!= NULL
)
354 ShDestruct(compiler_
);
357 void ShaderTranslator::ClearResults() {
358 translated_shader_
.reset();
361 uniform_map_
.clear();
362 varying_map_
.clear();