• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_translator.h"
6 
7 #include <string.h>
8 #include <algorithm>
9 
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"
15 
16 namespace {
17 
18 using gpu::gles2::ShaderTranslator;
19 
20 class ShaderTranslatorInitializer {
21  public:
ShaderTranslatorInitializer()22   ShaderTranslatorInitializer() {
23     TRACE_EVENT0("gpu", "ShInitialize");
24     CHECK(ShInitialize());
25   }
26 
~ShaderTranslatorInitializer()27   ~ShaderTranslatorInitializer() {
28     TRACE_EVENT0("gpu", "ShFinalize");
29     ShFinalize();
30   }
31 };
32 
33 base::LazyInstance<ShaderTranslatorInitializer> g_translator_initializer =
34     LAZY_INSTANCE_INITIALIZER;
35 
36 #if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
37 typedef int ANGLEGetInfoType;
38 #else
39 typedef size_t ANGLEGetInfoType;
40 #endif
41 
GetVariableInfo(ShHandle compiler,ShShaderInfo var_type,ShaderTranslator::VariableMap * var_map)42 void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
43                      ShaderTranslator::VariableMap* var_map) {
44   ANGLEGetInfoType name_len = 0, mapped_name_len = 0;
45   switch (var_type) {
46     case SH_ACTIVE_ATTRIBUTES:
47       ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len);
48       break;
49     case SH_ACTIVE_UNIFORMS:
50       ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
51       break;
52     case SH_VARYINGS:
53       ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
54       break;
55     default: NOTREACHED();
56   }
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]);
61 
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;
66     int size = 0;
67     ShDataType type = SH_NONE;
68     ShPrecisionType precision = SH_PRECISION_UNDEFINED;
69     int static_use = 0;
70 
71     ShGetVariableInfo(compiler, var_type, i,
72                       &len, &size, &type, &precision, &static_use,
73                       name.get(), mapped_name.get());
74 
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
78     // for mapped_name.
79     std::string name_string(name.get(), std::min(len, name_len - 1));
80     mapped_name.get()[mapped_name_len - 1] = '\0';
81 
82     ShaderTranslator::VariableInfo info(
83         type, size, precision, static_use, name_string);
84     (*var_map)[mapped_name.get()] = info;
85   }
86 }
87 
GetNameHashingInfo(ShHandle compiler,ShaderTranslator::NameMap * name_map)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)
93     return;
94 
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);
98 
99   scoped_ptr<char[]> name(new char[name_max_len]);
100   scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);
101 
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();
105   }
106 }
107 
108 }  // namespace
109 
110 namespace gpu {
111 namespace gles2 {
112 
DestructionObserver()113 ShaderTranslator::DestructionObserver::DestructionObserver() {
114 }
115 
~DestructionObserver()116 ShaderTranslator::DestructionObserver::~DestructionObserver() {
117 }
118 
ShaderTranslator()119 ShaderTranslator::ShaderTranslator()
120     : compiler_(NULL),
121       implementation_is_glsl_es_(false),
122       driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
123 }
124 
Init(ShShaderType shader_type,ShShaderSpec shader_spec,const ShBuiltInResources * resources,ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,ShCompileOptions driver_bug_workarounds)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);
136 
137   g_translator_initializer.Get();
138 
139   ShShaderOutput shader_output =
140       (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT);
141 
142   {
143     TRACE_EVENT0("gpu", "ShConstructCompiler");
144     compiler_ = ShConstructCompiler(
145         shader_type, shader_spec, shader_output, resources);
146   }
147   compiler_options_ = *resources;
148   implementation_is_glsl_es_ = (glsl_implementation_type == kGlslES);
149   driver_bug_workarounds_ = driver_bug_workarounds;
150   return compiler_ != NULL;
151 }
152 
GetCompileOptions() const153 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;
158 
159   compile_options |= driver_bug_workarounds_;
160 
161   return compile_options;
162 }
163 
Translate(const char * shader)164 bool ShaderTranslator::Translate(const char* shader) {
165   // Make sure this instance is initialized.
166   DCHECK(compiler_ != NULL);
167   DCHECK(shader != NULL);
168   ClearResults();
169 
170   bool success = false;
171   {
172     TRACE_EVENT0("gpu", "ShCompile");
173     success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions());
174   }
175   if (success) {
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());
182     }
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_);
189   }
190 
191   // Get info log.
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());
197   } else {
198     info_log_.reset();
199   }
200 
201   return success;
202 }
203 
GetStringForOptionsThatWouldAffectCompilation() const204 std::string ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation()
205     const {
206 #if ANGLE_SH_VERSION >= 124
207   DCHECK(compiler_ != NULL);
208 
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]);
213 
214   ShGetBuiltInResourcesString(compiler_, resource_len, resource_str.get());
215 
216   return std::string(":CompileOptions:" +
217          base::IntToString(GetCompileOptions())) +
218          std::string(resource_str.get());
219 #else
220 #if ANGLE_SH_VERSION >= 123
221   const size_t kNumIntFields = 21;
222 #elif ANGLE_SH_VERSION >= 122
223   const size_t kNumIntFields = 20;
224 #else
225   const size_t kNumIntFields = 16;
226 #endif
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);
231     enum Enum {
232       kFirst,
233     };
234     int int_fields[kNumIntFields];
235     FunctionPointer pointer_fields[kNumFunctionPointerFields];
236     Enum enum_fields[kNumEnumFields];
237   };
238   // If this assert fails most likely that means something below needs updating.
239   COMPILE_ASSERT(
240       sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource),
241       Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below);
242 
243   return std::string(
244       ":CompileOptions:" +
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) +
260       ":MaxDrawBuffers:" +
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) +
276       ":EXT_frag_depth:" +
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) +
282 #endif
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));
293 #endif
294 #endif
295 }
296 
translated_shader() const297 const char* ShaderTranslator::translated_shader() const {
298   return translated_shader_.get();
299 }
300 
info_log() const301 const char* ShaderTranslator::info_log() const {
302   return info_log_.get();
303 }
304 
305 const ShaderTranslatorInterface::VariableMap&
attrib_map() const306 ShaderTranslator::attrib_map() const {
307   return attrib_map_;
308 }
309 
310 const ShaderTranslatorInterface::VariableMap&
uniform_map() const311 ShaderTranslator::uniform_map() const {
312   return uniform_map_;
313 }
314 
315 const ShaderTranslatorInterface::VariableMap&
varying_map() const316 ShaderTranslator::varying_map() const {
317   return varying_map_;
318 }
319 
320 const ShaderTranslatorInterface::NameMap&
name_map() const321 ShaderTranslator::name_map() const {
322   return name_map_;
323 }
324 
AddDestructionObserver(DestructionObserver * observer)325 void ShaderTranslator::AddDestructionObserver(
326     DestructionObserver* observer) {
327   destruction_observers_.AddObserver(observer);
328 }
329 
RemoveDestructionObserver(DestructionObserver * observer)330 void ShaderTranslator::RemoveDestructionObserver(
331     DestructionObserver* observer) {
332   destruction_observers_.RemoveObserver(observer);
333 }
334 
~ShaderTranslator()335 ShaderTranslator::~ShaderTranslator() {
336   FOR_EACH_OBSERVER(DestructionObserver,
337                     destruction_observers_,
338                     OnDestruct(this));
339 
340   if (compiler_ != NULL)
341     ShDestruct(compiler_);
342 }
343 
ClearResults()344 void ShaderTranslator::ClearResults() {
345   translated_shader_.reset();
346   info_log_.reset();
347   attrib_map_.clear();
348   uniform_map_.clear();
349   varying_map_.clear();
350   name_map_.clear();
351 }
352 
353 }  // namespace gles2
354 }  // namespace gpu
355 
356