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