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/logging.h"
     13 #include "base/strings/string_number_conversions.h"
     14 
     15 namespace {
     16 
     17 using gpu::gles2::ShaderTranslator;
     18 
     19 void FinalizeShaderTranslator(void* /* dummy */) {
     20   TRACE_EVENT0("gpu", "ShFinalize");
     21   ShFinalize();
     22 }
     23 
     24 bool 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
     36 typedef int ANGLEGetInfoType;
     37 #else
     38 typedef size_t ANGLEGetInfoType;
     39 #endif
     40 
     41 void 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     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   ANGLEGetInfoType num_vars = 0;
     62   ShGetInfo(compiler, var_type, &num_vars);
     63   for (ANGLEGetInfoType i = 0; i < num_vars; ++i) {
     64     ANGLEGetInfoType len = 0;
     65     int size = 0;
     66     ShDataType type = SH_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   ANGLEGetInfoType hashed_names_count = 0;
     90   ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count);
     91   if (hashed_names_count == 0)
     92     return;
     93 
     94   ANGLEGetInfoType name_max_len = 0, hashed_name_max_len = 0;
     95   ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len);
     96   ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len);
     97 
     98   scoped_ptr<char[]> name(new char[name_max_len]);
     99   scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);
    100 
    101   for (ANGLEGetInfoType i = 0; i < hashed_names_count; ++i) {
    102     ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get());
    103     (*name_map)[hashed_name.get()] = name.get();
    104   }
    105 }
    106 
    107 }  // namespace
    108 
    109 namespace gpu {
    110 namespace gles2 {
    111 
    112 ShaderTranslator::DestructionObserver::DestructionObserver() {
    113 }
    114 
    115 ShaderTranslator::DestructionObserver::~DestructionObserver() {
    116 }
    117 
    118 ShaderTranslator::ShaderTranslator()
    119     : compiler_(NULL),
    120       implementation_is_glsl_es_(false),
    121       driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
    122 }
    123 
    124 bool ShaderTranslator::Init(
    125     ShShaderType shader_type,
    126     ShShaderSpec shader_spec,
    127     const ShBuiltInResources* resources,
    128     ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,
    129     ShCompileOptions driver_bug_workarounds) {
    130   // Make sure Init is called only once.
    131   DCHECK(compiler_ == NULL);
    132   DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER);
    133   DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC);
    134   DCHECK(resources != NULL);
    135 
    136   if (!InitializeShaderTranslator())
    137     return false;
    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 |
    156       SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS |
    157       SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH;
    158 
    159   compile_options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
    160 
    161   compile_options |= driver_bug_workarounds_;
    162 
    163   return compile_options;
    164 }
    165 
    166 bool 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 
    206 std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation()
    207     const {
    208   const size_t kNumIntFields = 16;
    209   const size_t kNumEnumFields = 1;
    210   const size_t kNumFunctionPointerFields = 1;
    211   struct MustMatchShBuiltInResource {
    212     typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t);
    213     enum Enum {
    214       kFirst,
    215     };
    216     int int_fields[kNumIntFields];
    217     FunctionPointer pointer_fields[kNumFunctionPointerFields];
    218     Enum enum_fields[kNumEnumFields];
    219   };
    220   // If this assert fails most likely that means something below needs updating.
    221   COMPILE_ASSERT(
    222       sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource),
    223       Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below);
    224 
    225   return std::string(
    226       ":CompileOptions:" +
    227       base::IntToString(GetCompileOptions()) +
    228       ":MaxVertexAttribs:" +
    229       base::IntToString(compiler_options_.MaxVertexAttribs) +
    230       ":MaxVertexUniformVectors:" +
    231       base::IntToString(compiler_options_.MaxVertexUniformVectors) +
    232       ":MaxVaryingVectors:" +
    233       base::IntToString(compiler_options_.MaxVaryingVectors) +
    234       ":MaxVertexTextureImageUnits:" +
    235       base::IntToString(compiler_options_.MaxVertexTextureImageUnits) +
    236       ":MaxCombinedTextureImageUnits:" +
    237       base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) +
    238       ":MaxTextureImageUnits:" +
    239       base::IntToString(compiler_options_.MaxTextureImageUnits) +
    240       ":MaxFragmentUniformVectors:" +
    241       base::IntToString(compiler_options_.MaxFragmentUniformVectors) +
    242       ":MaxDrawBuffers:" +
    243       base::IntToString(compiler_options_.MaxDrawBuffers) +
    244       ":OES_standard_derivatives:" +
    245       base::IntToString(compiler_options_.OES_standard_derivatives) +
    246       ":OES_EGL_image_external:" +
    247       base::IntToString(compiler_options_.OES_EGL_image_external) +
    248       ":ARB_texture_rectangle:" +
    249       base::IntToString(compiler_options_.ARB_texture_rectangle) +
    250       ":EXT_draw_buffers:" +
    251       base::IntToString(compiler_options_.EXT_draw_buffers) +
    252       ":FragmentPrecisionHigh:" +
    253       base::IntToString(compiler_options_.FragmentPrecisionHigh) +
    254       ":MaxExpressionComplexity:" +
    255       base::IntToString(compiler_options_.MaxExpressionComplexity) +
    256       ":MaxCallStackDepth:" +
    257       base::IntToString(compiler_options_.MaxCallStackDepth) +
    258       ":EXT_frag_depth:" +
    259       base::IntToString(compiler_options_.EXT_frag_depth));
    260 }
    261 
    262 const char* ShaderTranslator::translated_shader() const {
    263   return translated_shader_.get();
    264 }
    265 
    266 const char* ShaderTranslator::info_log() const {
    267   return info_log_.get();
    268 }
    269 
    270 const ShaderTranslatorInterface::VariableMap&
    271 ShaderTranslator::attrib_map() const {
    272   return attrib_map_;
    273 }
    274 
    275 const ShaderTranslatorInterface::VariableMap&
    276 ShaderTranslator::uniform_map() const {
    277   return uniform_map_;
    278 }
    279 
    280 const ShaderTranslatorInterface::VariableMap&
    281 ShaderTranslator::varying_map() const {
    282   return varying_map_;
    283 }
    284 
    285 const ShaderTranslatorInterface::NameMap&
    286 ShaderTranslator::name_map() const {
    287   return name_map_;
    288 }
    289 
    290 void ShaderTranslator::AddDestructionObserver(
    291     DestructionObserver* observer) {
    292   destruction_observers_.AddObserver(observer);
    293 }
    294 
    295 void ShaderTranslator::RemoveDestructionObserver(
    296     DestructionObserver* observer) {
    297   destruction_observers_.RemoveObserver(observer);
    298 }
    299 
    300 ShaderTranslator::~ShaderTranslator() {
    301   FOR_EACH_OBSERVER(DestructionObserver,
    302                     destruction_observers_,
    303                     OnDestruct(this));
    304 
    305   if (compiler_ != NULL)
    306     ShDestruct(compiler_);
    307 }
    308 
    309 void ShaderTranslator::ClearResults() {
    310   translated_shader_.reset();
    311   info_log_.reset();
    312   attrib_map_.clear();
    313   uniform_map_.clear();
    314   varying_map_.clear();
    315   name_map_.clear();
    316 }
    317 
    318 }  // namespace gles2
    319 }  // namespace gpu
    320 
    321