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