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 <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:
     22   ShaderTranslatorInitializer() {
     23     TRACE_EVENT0("gpu", "ShInitialize");
     24     CHECK(ShInitialize());
     25   }
     26 
     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 
     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 
     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 
    113 ShaderTranslator::DestructionObserver::DestructionObserver() {
    114 }
    115 
    116 ShaderTranslator::DestructionObserver::~DestructionObserver() {
    117 }
    118 
    119 ShaderTranslator::ShaderTranslator()
    120     : compiler_(NULL),
    121       implementation_is_glsl_es_(false),
    122       driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
    123 }
    124 
    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 
    153 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 
    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 
    204 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 
    297 const char* ShaderTranslator::translated_shader() const {
    298   return translated_shader_.get();
    299 }
    300 
    301 const char* ShaderTranslator::info_log() const {
    302   return info_log_.get();
    303 }
    304 
    305 const ShaderTranslatorInterface::VariableMap&
    306 ShaderTranslator::attrib_map() const {
    307   return attrib_map_;
    308 }
    309 
    310 const ShaderTranslatorInterface::VariableMap&
    311 ShaderTranslator::uniform_map() const {
    312   return uniform_map_;
    313 }
    314 
    315 const ShaderTranslatorInterface::VariableMap&
    316 ShaderTranslator::varying_map() const {
    317   return varying_map_;
    318 }
    319 
    320 const ShaderTranslatorInterface::NameMap&
    321 ShaderTranslator::name_map() const {
    322   return name_map_;
    323 }
    324 
    325 void ShaderTranslator::AddDestructionObserver(
    326     DestructionObserver* observer) {
    327   destruction_observers_.AddObserver(observer);
    328 }
    329 
    330 void ShaderTranslator::RemoveDestructionObserver(
    331     DestructionObserver* observer) {
    332   destruction_observers_.RemoveObserver(observer);
    333 }
    334 
    335 ShaderTranslator::~ShaderTranslator() {
    336   FOR_EACH_OBSERVER(DestructionObserver,
    337                     destruction_observers_,
    338                     OnDestruct(this));
    339 
    340   if (compiler_ != NULL)
    341     ShDestruct(compiler_);
    342 }
    343 
    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