Home | History | Annotate | Download | only in service
      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 <GLES2/gl2.h>
      9 #include <algorithm>
     10 
     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"
     16 
     17 namespace {
     18 
     19 using gpu::gles2::ShaderTranslator;
     20 
     21 class ShaderTranslatorInitializer {
     22  public:
     23   ShaderTranslatorInitializer() {
     24     TRACE_EVENT0("gpu", "ShInitialize");
     25     CHECK(ShInitialize());
     26   }
     27 
     28   ~ShaderTranslatorInitializer() {
     29     TRACE_EVENT0("gpu", "ShFinalize");
     30     ShFinalize();
     31   }
     32 };
     33 
     34 base::LazyInstance<ShaderTranslatorInitializer> g_translator_initializer =
     35     LAZY_INSTANCE_INITIALIZER;
     36 
     37 void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
     38                      ShaderTranslator::VariableMap* var_map) {
     39   if (!var_map)
     40     return;
     41   var_map->clear();
     42 
     43   size_t 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     case SH_VARYINGS:
     52       ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
     53       break;
     54     default: NOTREACHED();
     55   }
     56   ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
     57   if (name_len <= 1 || mapped_name_len <= 1) return;
     58   scoped_ptr<char[]> name(new char[name_len]);
     59   scoped_ptr<char[]> mapped_name(new char[mapped_name_len]);
     60 
     61   size_t num_vars = 0;
     62   ShGetInfo(compiler, var_type, &num_vars);
     63   for (size_t i = 0; i < num_vars; ++i) {
     64     size_t len = 0;
     65     int size = 0;
     66     sh::GLenum type = GL_NONE;
     67     ShPrecisionType precision = SH_PRECISION_UNDEFINED;
     68     int static_use = 0;
     69 
     70     ShGetVariableInfo(compiler, var_type, i,
     71                       &len, &size, &type, &precision, &static_use,
     72                       name.get(), mapped_name.get());
     73 
     74     // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
     75     // to handle long struct field name mapping before we can do this.
     76     // Also, we should modify the ANGLE interface to also return a length
     77     // for mapped_name.
     78     std::string name_string(name.get(), std::min(len, name_len - 1));
     79     mapped_name.get()[mapped_name_len - 1] = '\0';
     80 
     81     ShaderTranslator::VariableInfo info(
     82         type, size, precision, static_use, name_string);
     83     (*var_map)[mapped_name.get()] = info;
     84   }
     85 }
     86 
     87 void GetNameHashingInfo(
     88     ShHandle compiler, ShaderTranslator::NameMap* name_map) {
     89   if (!name_map)
     90     return;
     91   name_map->clear();
     92 
     93   size_t hashed_names_count = 0;
     94   ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count);
     95   if (hashed_names_count == 0)
     96     return;
     97 
     98   size_t name_max_len = 0, hashed_name_max_len = 0;
     99   ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len);
    100   ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len);
    101 
    102   scoped_ptr<char[]> name(new char[name_max_len]);
    103   scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);
    104 
    105   for (size_t i = 0; i < hashed_names_count; ++i) {
    106     ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get());
    107     (*name_map)[hashed_name.get()] = name.get();
    108   }
    109 }
    110 
    111 }  // namespace
    112 
    113 namespace gpu {
    114 namespace gles2 {
    115 
    116 ShaderTranslator::DestructionObserver::DestructionObserver() {
    117 }
    118 
    119 ShaderTranslator::DestructionObserver::~DestructionObserver() {
    120 }
    121 
    122 ShaderTranslator::ShaderTranslator()
    123     : compiler_(NULL),
    124       implementation_is_glsl_es_(false),
    125       driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
    126 }
    127 
    128 bool ShaderTranslator::Init(
    129     GLenum shader_type,
    130     ShShaderSpec shader_spec,
    131     const ShBuiltInResources* resources,
    132     ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,
    133     ShCompileOptions driver_bug_workarounds) {
    134   // Make sure Init is called only once.
    135   DCHECK(compiler_ == NULL);
    136   DCHECK(shader_type == GL_FRAGMENT_SHADER || shader_type == GL_VERTEX_SHADER);
    137   DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC);
    138   DCHECK(resources != NULL);
    139 
    140   g_translator_initializer.Get();
    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   driver_bug_workarounds_ = driver_bug_workarounds;
    153   return compiler_ != NULL;
    154 }
    155 
    156 int ShaderTranslator::GetCompileOptions() const {
    157   int compile_options =
    158       SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS |
    159       SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH |
    160       SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
    161 
    162   compile_options |= driver_bug_workarounds_;
    163 
    164   return compile_options;
    165 }
    166 
    167 bool ShaderTranslator::Translate(const std::string& shader_source,
    168                                  std::string* info_log,
    169                                  std::string* translated_source,
    170                                  VariableMap* attrib_map,
    171                                  VariableMap* uniform_map,
    172                                  VariableMap* varying_map,
    173                                  NameMap* name_map) const {
    174   // Make sure this instance is initialized.
    175   DCHECK(compiler_ != NULL);
    176 
    177   bool success = false;
    178   {
    179     TRACE_EVENT0("gpu", "ShCompile");
    180     const char* const shader_strings[] = { shader_source.c_str() };
    181     success = !!ShCompile(
    182         compiler_, shader_strings, 1, GetCompileOptions());
    183   }
    184   if (success) {
    185     if (translated_source) {
    186       translated_source->clear();
    187       // Get translated shader.
    188       size_t obj_code_len = 0;
    189       ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len);
    190       if (obj_code_len > 1) {
    191         scoped_ptr<char[]> buffer(new char[obj_code_len]);
    192         ShGetObjectCode(compiler_, buffer.get());
    193         *translated_source = std::string(buffer.get(), obj_code_len - 1);
    194       }
    195     }
    196     // Get info for attribs, uniforms, and varyings.
    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);
    202   }
    203 
    204   // Get info log.
    205   if (info_log) {
    206     info_log->clear();
    207     size_t info_log_len = 0;
    208     ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len);
    209     if (info_log_len > 1) {
    210       scoped_ptr<char[]> buffer(new char[info_log_len]);
    211       ShGetInfoLog(compiler_, buffer.get());
    212       *info_log = std::string(buffer.get(), info_log_len - 1);
    213     }
    214   }
    215 
    216   return success;
    217 }
    218 
    219 std::string ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation()
    220     const {
    221   DCHECK(compiler_ != NULL);
    222 
    223   size_t resource_len = 0;
    224   ShGetInfo(compiler_, SH_RESOURCES_STRING_LENGTH, &resource_len);
    225   DCHECK(resource_len > 1);
    226   scoped_ptr<char[]> resource_str(new char[resource_len]);
    227 
    228   ShGetBuiltInResourcesString(compiler_, resource_len, resource_str.get());
    229 
    230   return std::string(":CompileOptions:" +
    231          base::IntToString(GetCompileOptions())) +
    232          std::string(resource_str.get());
    233 }
    234 
    235 void ShaderTranslator::AddDestructionObserver(
    236     DestructionObserver* observer) {
    237   destruction_observers_.AddObserver(observer);
    238 }
    239 
    240 void ShaderTranslator::RemoveDestructionObserver(
    241     DestructionObserver* observer) {
    242   destruction_observers_.RemoveObserver(observer);
    243 }
    244 
    245 ShaderTranslator::~ShaderTranslator() {
    246   FOR_EACH_OBSERVER(DestructionObserver,
    247                     destruction_observers_,
    248                     OnDestruct(this));
    249 
    250   if (compiler_ != NULL)
    251     ShDestruct(compiler_);
    252 }
    253 
    254 }  // namespace gles2
    255 }  // namespace gpu
    256 
    257