shader_translator.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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/logging.h"
13#include "base/strings/string_number_conversions.h"
14
15namespace {
16
17using gpu::gles2::ShaderTranslator;
18
19bool g_translator_initialized = false;
20
21void FinalizeShaderTranslator(void* /* dummy */) {
22  TRACE_EVENT0("gpu", "ShFinalize");
23  ShFinalize();
24  g_translator_initialized = false;
25}
26
27bool InitializeShaderTranslator() {
28  if (!g_translator_initialized) {
29    TRACE_EVENT0("gpu", "ShInitialize");
30    CHECK(ShInitialize());
31    base::AtExitManager::RegisterCallback(&FinalizeShaderTranslator, NULL);
32    g_translator_initialized = true;
33  }
34  return g_translator_initialized;
35}
36
37#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
38typedef int ANGLEGetInfoType;
39#else
40typedef size_t ANGLEGetInfoType;
41#endif
42
43void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
44                     ShaderTranslator::VariableMap* var_map) {
45  ANGLEGetInfoType name_len = 0, mapped_name_len = 0;
46  switch (var_type) {
47    case SH_ACTIVE_ATTRIBUTES:
48      ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len);
49      break;
50    case SH_ACTIVE_UNIFORMS:
51      ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
52      break;
53    case SH_VARYINGS:
54      ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
55      break;
56    default: NOTREACHED();
57  }
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]);
62
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;
67    int size = 0;
68    ShDataType type = SH_NONE;
69    ShPrecisionType precision = SH_PRECISION_UNDEFINED;
70    int static_use = 0;
71
72    ShGetVariableInfo(compiler, var_type, i,
73                      &len, &size, &type, &precision, &static_use,
74                      name.get(), mapped_name.get());
75
76    // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
77    // to handle long struct field name mapping before we can do this.
78    // Also, we should modify the ANGLE interface to also return a length
79    // for mapped_name.
80    std::string name_string(name.get(), std::min(len, name_len - 1));
81    mapped_name.get()[mapped_name_len - 1] = '\0';
82
83    ShaderTranslator::VariableInfo info(
84        type, size, precision, static_use, name_string);
85    (*var_map)[mapped_name.get()] = info;
86  }
87}
88
89void GetNameHashingInfo(
90    ShHandle compiler, ShaderTranslator::NameMap* name_map) {
91  ANGLEGetInfoType hashed_names_count = 0;
92  ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count);
93  if (hashed_names_count == 0)
94    return;
95
96  ANGLEGetInfoType name_max_len = 0, hashed_name_max_len = 0;
97  ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len);
98  ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len);
99
100  scoped_ptr<char[]> name(new char[name_max_len]);
101  scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);
102
103  for (ANGLEGetInfoType i = 0; i < hashed_names_count; ++i) {
104    ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get());
105    (*name_map)[hashed_name.get()] = name.get();
106  }
107}
108
109}  // namespace
110
111namespace gpu {
112namespace gles2 {
113
114ShaderTranslator::DestructionObserver::DestructionObserver() {
115}
116
117ShaderTranslator::DestructionObserver::~DestructionObserver() {
118}
119
120ShaderTranslator::ShaderTranslator()
121    : compiler_(NULL),
122      implementation_is_glsl_es_(false),
123      driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
124}
125
126bool ShaderTranslator::Init(
127    ShShaderType shader_type,
128    ShShaderSpec shader_spec,
129    const ShBuiltInResources* resources,
130    ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,
131    ShCompileOptions driver_bug_workarounds) {
132  // Make sure Init is called only once.
133  DCHECK(compiler_ == NULL);
134  DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER);
135  DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC);
136  DCHECK(resources != NULL);
137
138  if (!InitializeShaderTranslator())
139    return false;
140
141  ShShaderOutput shader_output =
142      (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT);
143
144  {
145    TRACE_EVENT0("gpu", "ShConstructCompiler");
146    compiler_ = ShConstructCompiler(
147        shader_type, shader_spec, shader_output, resources);
148  }
149  compiler_options_ = *resources;
150  implementation_is_glsl_es_ = (glsl_implementation_type == kGlslES);
151  driver_bug_workarounds_ = driver_bug_workarounds;
152  return compiler_ != NULL;
153}
154
155int ShaderTranslator::GetCompileOptions() const {
156  int compile_options =
157      SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS |
158      SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH |
159      SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
160
161  compile_options |= driver_bug_workarounds_;
162
163  return compile_options;
164}
165
166bool ShaderTranslator::Translate(const char* shader) {
167  // Make sure this instance is initialized.
168  DCHECK(compiler_ != NULL);
169  DCHECK(shader != NULL);
170  ClearResults();
171
172  bool success = false;
173  {
174    TRACE_EVENT0("gpu", "ShCompile");
175    success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions());
176  }
177  if (success) {
178    // Get translated shader.
179    ANGLEGetInfoType obj_code_len = 0;
180    ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len);
181    if (obj_code_len > 1) {
182      translated_shader_.reset(new char[obj_code_len]);
183      ShGetObjectCode(compiler_, translated_shader_.get());
184    }
185    // Get info for attribs and uniforms.
186    GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_);
187    GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_);
188    GetVariableInfo(compiler_, SH_VARYINGS, &varying_map_);
189    // Get info for name hashing.
190    GetNameHashingInfo(compiler_, &name_map_);
191  }
192
193  // Get info log.
194  ANGLEGetInfoType info_log_len = 0;
195  ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len);
196  if (info_log_len > 1) {
197    info_log_.reset(new char[info_log_len]);
198    ShGetInfoLog(compiler_, info_log_.get());
199  } else {
200    info_log_.reset();
201  }
202
203  return success;
204}
205
206std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation()
207    const {
208
209#if ANGLE_SH_VERSION >= 122
210  const size_t kNumIntFields = 20;
211#else
212  const size_t kNumIntFields = 16;
213#endif
214  const size_t kNumEnumFields = 1;
215  const size_t kNumFunctionPointerFields = 1;
216  struct MustMatchShBuiltInResource {
217    typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t);
218    enum Enum {
219      kFirst,
220    };
221    int int_fields[kNumIntFields];
222    FunctionPointer pointer_fields[kNumFunctionPointerFields];
223    Enum enum_fields[kNumEnumFields];
224  };
225  // If this assert fails most likely that means something below needs updating.
226  COMPILE_ASSERT(
227      sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource),
228      Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below);
229
230  return std::string(
231      ":CompileOptions:" +
232      base::IntToString(GetCompileOptions()) +
233      ":MaxVertexAttribs:" +
234      base::IntToString(compiler_options_.MaxVertexAttribs) +
235      ":MaxVertexUniformVectors:" +
236      base::IntToString(compiler_options_.MaxVertexUniformVectors) +
237      ":MaxVaryingVectors:" +
238      base::IntToString(compiler_options_.MaxVaryingVectors) +
239      ":MaxVertexTextureImageUnits:" +
240      base::IntToString(compiler_options_.MaxVertexTextureImageUnits) +
241      ":MaxCombinedTextureImageUnits:" +
242      base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) +
243      ":MaxTextureImageUnits:" +
244      base::IntToString(compiler_options_.MaxTextureImageUnits) +
245      ":MaxFragmentUniformVectors:" +
246      base::IntToString(compiler_options_.MaxFragmentUniformVectors) +
247      ":MaxDrawBuffers:" +
248      base::IntToString(compiler_options_.MaxDrawBuffers) +
249      ":OES_standard_derivatives:" +
250      base::IntToString(compiler_options_.OES_standard_derivatives) +
251      ":OES_EGL_image_external:" +
252      base::IntToString(compiler_options_.OES_EGL_image_external) +
253      ":ARB_texture_rectangle:" +
254      base::IntToString(compiler_options_.ARB_texture_rectangle) +
255      ":EXT_draw_buffers:" +
256      base::IntToString(compiler_options_.EXT_draw_buffers) +
257      ":FragmentPrecisionHigh:" +
258      base::IntToString(compiler_options_.FragmentPrecisionHigh) +
259      ":MaxExpressionComplexity:" +
260      base::IntToString(compiler_options_.MaxExpressionComplexity) +
261      ":MaxCallStackDepth:" +
262      base::IntToString(compiler_options_.MaxCallStackDepth) +
263      ":EXT_frag_depth:" +
264#if ANGLE_SH_VERSION >= 122
265      base::IntToString(compiler_options_.EXT_frag_depth) +
266      ":MaxVertexOutputVectors:" +
267      base::IntToString(compiler_options_.MaxVertexOutputVectors) +
268      ":MaxFragmentInputVectors:" +
269      base::IntToString(compiler_options_.MaxFragmentInputVectors) +
270      ":MinProgramTexelOffset:" +
271      base::IntToString(compiler_options_.MinProgramTexelOffset) +
272      ":MaxProgramTexelOffset:" +
273      base::IntToString(compiler_options_.MaxProgramTexelOffset));
274#else
275      base::IntToString(compiler_options_.EXT_frag_depth));
276#endif
277}
278
279const char* ShaderTranslator::translated_shader() const {
280  return translated_shader_.get();
281}
282
283const char* ShaderTranslator::info_log() const {
284  return info_log_.get();
285}
286
287const ShaderTranslatorInterface::VariableMap&
288ShaderTranslator::attrib_map() const {
289  return attrib_map_;
290}
291
292const ShaderTranslatorInterface::VariableMap&
293ShaderTranslator::uniform_map() const {
294  return uniform_map_;
295}
296
297const ShaderTranslatorInterface::VariableMap&
298ShaderTranslator::varying_map() const {
299  return varying_map_;
300}
301
302const ShaderTranslatorInterface::NameMap&
303ShaderTranslator::name_map() const {
304  return name_map_;
305}
306
307void ShaderTranslator::AddDestructionObserver(
308    DestructionObserver* observer) {
309  destruction_observers_.AddObserver(observer);
310}
311
312void ShaderTranslator::RemoveDestructionObserver(
313    DestructionObserver* observer) {
314  destruction_observers_.RemoveObserver(observer);
315}
316
317ShaderTranslator::~ShaderTranslator() {
318  FOR_EACH_OBSERVER(DestructionObserver,
319                    destruction_observers_,
320                    OnDestruct(this));
321
322  if (compiler_ != NULL)
323    ShDestruct(compiler_);
324}
325
326void ShaderTranslator::ClearResults() {
327  translated_shader_.reset();
328  info_log_.reset();
329  attrib_map_.clear();
330  uniform_map_.clear();
331  varying_map_.clear();
332  name_map_.clear();
333}
334
335}  // namespace gles2
336}  // namespace gpu
337
338