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     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 
     89 void 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 
    111 namespace gpu {
    112 namespace gles2 {
    113 
    114 ShaderTranslator::DestructionObserver::DestructionObserver() {
    115 }
    116 
    117 ShaderTranslator::DestructionObserver::~DestructionObserver() {
    118 }
    119 
    120 ShaderTranslator::ShaderTranslator()
    121     : compiler_(NULL),
    122       implementation_is_glsl_es_(false),
    123       needs_built_in_function_emulation_(false) {
    124 }
    125 
    126 bool 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 
    157 int 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 
    171 bool 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 
    210 std::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 
    266 const char* ShaderTranslator::translated_shader() const {
    267   return translated_shader_.get();
    268 }
    269 
    270 const char* ShaderTranslator::info_log() const {
    271   return info_log_.get();
    272 }
    273 
    274 const ShaderTranslatorInterface::VariableMap&
    275 ShaderTranslator::attrib_map() const {
    276   return attrib_map_;
    277 }
    278 
    279 const ShaderTranslatorInterface::VariableMap&
    280 ShaderTranslator::uniform_map() const {
    281   return uniform_map_;
    282 }
    283 
    284 const ShaderTranslatorInterface::NameMap&
    285 ShaderTranslator::name_map() const {
    286   return name_map_;
    287 }
    288 
    289 void ShaderTranslator::AddDestructionObserver(
    290     DestructionObserver* observer) {
    291   destruction_observers_.AddObserver(observer);
    292 }
    293 
    294 void ShaderTranslator::RemoveDestructionObserver(
    295     DestructionObserver* observer) {
    296   destruction_observers_.RemoveObserver(observer);
    297 }
    298 
    299 ShaderTranslator::~ShaderTranslator() {
    300   FOR_EACH_OBSERVER(DestructionObserver,
    301                     destruction_observers_,
    302                     OnDestruct(this));
    303 
    304   if (compiler_ != NULL)
    305     ShDestruct(compiler_);
    306 }
    307 
    308 void 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