root/gpu/command_buffer/service/shader_translator.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetVariableInfo
  2. GetNameHashingInfo
  3. driver_bug_workarounds_
  4. Init
  5. GetCompileOptions
  6. Translate
  7. GetStringForOptionsThatWouldEffectCompilation
  8. translated_shader
  9. info_log
  10. attrib_map
  11. uniform_map
  12. varying_map
  13. name_map
  14. AddDestructionObserver
  15. RemoveDestructionObserver
  16. ClearResults

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/shader_translator.h"

#include <string.h>
#include <algorithm>

#include "base/at_exit.h"
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"

namespace {

using gpu::gles2::ShaderTranslator;

class ShaderTranslatorInitializer {
 public:
  ShaderTranslatorInitializer() {
    TRACE_EVENT0("gpu", "ShInitialize");
    CHECK(ShInitialize());
  }

  ~ShaderTranslatorInitializer() {
    TRACE_EVENT0("gpu", "ShFinalize");
    ShFinalize();
  }
};

base::LazyInstance<ShaderTranslatorInitializer> g_translator_initializer =
    LAZY_INSTANCE_INITIALIZER;

#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
typedef int ANGLEGetInfoType;
#else
typedef size_t ANGLEGetInfoType;
#endif

void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
                     ShaderTranslator::VariableMap* var_map) {
  ANGLEGetInfoType name_len = 0, mapped_name_len = 0;
  switch (var_type) {
    case SH_ACTIVE_ATTRIBUTES:
      ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len);
      break;
    case SH_ACTIVE_UNIFORMS:
      ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
      break;
    case SH_VARYINGS:
      ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len);
      break;
    default: NOTREACHED();
  }
  ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
  if (name_len <= 1 || mapped_name_len <= 1) return;
  scoped_ptr<char[]> name(new char[name_len]);
  scoped_ptr<char[]> mapped_name(new char[mapped_name_len]);

  ANGLEGetInfoType num_vars = 0;
  ShGetInfo(compiler, var_type, &num_vars);
  for (ANGLEGetInfoType i = 0; i < num_vars; ++i) {
    ANGLEGetInfoType len = 0;
    int size = 0;
    ShDataType type = SH_NONE;
    ShPrecisionType precision = SH_PRECISION_UNDEFINED;
    int static_use = 0;

    ShGetVariableInfo(compiler, var_type, i,
                      &len, &size, &type, &precision, &static_use,
                      name.get(), mapped_name.get());

    // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
    // to handle long struct field name mapping before we can do this.
    // Also, we should modify the ANGLE interface to also return a length
    // for mapped_name.
    std::string name_string(name.get(), std::min(len, name_len - 1));
    mapped_name.get()[mapped_name_len - 1] = '\0';

    ShaderTranslator::VariableInfo info(
        type, size, precision, static_use, name_string);
    (*var_map)[mapped_name.get()] = info;
  }
}

void GetNameHashingInfo(
    ShHandle compiler, ShaderTranslator::NameMap* name_map) {
  ANGLEGetInfoType hashed_names_count = 0;
  ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count);
  if (hashed_names_count == 0)
    return;

  ANGLEGetInfoType name_max_len = 0, hashed_name_max_len = 0;
  ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len);
  ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len);

  scoped_ptr<char[]> name(new char[name_max_len]);
  scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);

  for (ANGLEGetInfoType i = 0; i < hashed_names_count; ++i) {
    ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get());
    (*name_map)[hashed_name.get()] = name.get();
  }
}

}  // namespace

namespace gpu {
namespace gles2 {

ShaderTranslator::DestructionObserver::DestructionObserver() {
}

ShaderTranslator::DestructionObserver::~DestructionObserver() {
}

ShaderTranslator::ShaderTranslator()
    : compiler_(NULL),
      implementation_is_glsl_es_(false),
      driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) {
}

bool ShaderTranslator::Init(
    ShShaderType shader_type,
    ShShaderSpec shader_spec,
    const ShBuiltInResources* resources,
    ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,
    ShCompileOptions driver_bug_workarounds) {
  // Make sure Init is called only once.
  DCHECK(compiler_ == NULL);
  DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER);
  DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC);
  DCHECK(resources != NULL);

  g_translator_initializer.Get();

  ShShaderOutput shader_output =
      (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT);

  {
    TRACE_EVENT0("gpu", "ShConstructCompiler");
    compiler_ = ShConstructCompiler(
        shader_type, shader_spec, shader_output, resources);
  }
  compiler_options_ = *resources;
  implementation_is_glsl_es_ = (glsl_implementation_type == kGlslES);
  driver_bug_workarounds_ = driver_bug_workarounds;
  return compiler_ != NULL;
}

int ShaderTranslator::GetCompileOptions() const {
  int compile_options =
      SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS |
      SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH |
      SH_CLAMP_INDIRECT_ARRAY_BOUNDS;

  compile_options |= driver_bug_workarounds_;

  return compile_options;
}

bool ShaderTranslator::Translate(const char* shader) {
  // Make sure this instance is initialized.
  DCHECK(compiler_ != NULL);
  DCHECK(shader != NULL);
  ClearResults();

  bool success = false;
  {
    TRACE_EVENT0("gpu", "ShCompile");
    success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions());
  }
  if (success) {
    // Get translated shader.
    ANGLEGetInfoType obj_code_len = 0;
    ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len);
    if (obj_code_len > 1) {
      translated_shader_.reset(new char[obj_code_len]);
      ShGetObjectCode(compiler_, translated_shader_.get());
    }
    // Get info for attribs and uniforms.
    GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_);
    GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_);
    GetVariableInfo(compiler_, SH_VARYINGS, &varying_map_);
    // Get info for name hashing.
    GetNameHashingInfo(compiler_, &name_map_);
  }

  // Get info log.
  ANGLEGetInfoType info_log_len = 0;
  ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len);
  if (info_log_len > 1) {
    info_log_.reset(new char[info_log_len]);
    ShGetInfoLog(compiler_, info_log_.get());
  } else {
    info_log_.reset();
  }

  return success;
}

std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation()
    const {

#if ANGLE_SH_VERSION >= 122
  const size_t kNumIntFields = 20;
#else
  const size_t kNumIntFields = 16;
#endif
  const size_t kNumEnumFields = 1;
  const size_t kNumFunctionPointerFields = 1;
  struct MustMatchShBuiltInResource {
    typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t);
    enum Enum {
      kFirst,
    };
    int int_fields[kNumIntFields];
    FunctionPointer pointer_fields[kNumFunctionPointerFields];
    Enum enum_fields[kNumEnumFields];
  };
  // If this assert fails most likely that means something below needs updating.
  COMPILE_ASSERT(
      sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource),
      Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below);

  return std::string(
      ":CompileOptions:" +
      base::IntToString(GetCompileOptions()) +
      ":MaxVertexAttribs:" +
      base::IntToString(compiler_options_.MaxVertexAttribs) +
      ":MaxVertexUniformVectors:" +
      base::IntToString(compiler_options_.MaxVertexUniformVectors) +
      ":MaxVaryingVectors:" +
      base::IntToString(compiler_options_.MaxVaryingVectors) +
      ":MaxVertexTextureImageUnits:" +
      base::IntToString(compiler_options_.MaxVertexTextureImageUnits) +
      ":MaxCombinedTextureImageUnits:" +
      base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) +
      ":MaxTextureImageUnits:" +
      base::IntToString(compiler_options_.MaxTextureImageUnits) +
      ":MaxFragmentUniformVectors:" +
      base::IntToString(compiler_options_.MaxFragmentUniformVectors) +
      ":MaxDrawBuffers:" +
      base::IntToString(compiler_options_.MaxDrawBuffers) +
      ":OES_standard_derivatives:" +
      base::IntToString(compiler_options_.OES_standard_derivatives) +
      ":OES_EGL_image_external:" +
      base::IntToString(compiler_options_.OES_EGL_image_external) +
      ":ARB_texture_rectangle:" +
      base::IntToString(compiler_options_.ARB_texture_rectangle) +
      ":EXT_draw_buffers:" +
      base::IntToString(compiler_options_.EXT_draw_buffers) +
      ":FragmentPrecisionHigh:" +
      base::IntToString(compiler_options_.FragmentPrecisionHigh) +
      ":MaxExpressionComplexity:" +
      base::IntToString(compiler_options_.MaxExpressionComplexity) +
      ":MaxCallStackDepth:" +
      base::IntToString(compiler_options_.MaxCallStackDepth) +
      ":EXT_frag_depth:" +
#if ANGLE_SH_VERSION >= 122
      base::IntToString(compiler_options_.EXT_frag_depth) +
      ":MaxVertexOutputVectors:" +
      base::IntToString(compiler_options_.MaxVertexOutputVectors) +
      ":MaxFragmentInputVectors:" +
      base::IntToString(compiler_options_.MaxFragmentInputVectors) +
      ":MinProgramTexelOffset:" +
      base::IntToString(compiler_options_.MinProgramTexelOffset) +
      ":MaxProgramTexelOffset:" +
      base::IntToString(compiler_options_.MaxProgramTexelOffset));
#else
      base::IntToString(compiler_options_.EXT_frag_depth));
#endif
}

const char* ShaderTranslator::translated_shader() const {
  return translated_shader_.get();
}

const char* ShaderTranslator::info_log() const {
  return info_log_.get();
}

const ShaderTranslatorInterface::VariableMap&
ShaderTranslator::attrib_map() const {
  return attrib_map_;
}

const ShaderTranslatorInterface::VariableMap&
ShaderTranslator::uniform_map() const {
  return uniform_map_;
}

const ShaderTranslatorInterface::VariableMap&
ShaderTranslator::varying_map() const {
  return varying_map_;
}

const ShaderTranslatorInterface::NameMap&
ShaderTranslator::name_map() const {
  return name_map_;
}

void ShaderTranslator::AddDestructionObserver(
    DestructionObserver* observer) {
  destruction_observers_.AddObserver(observer);
}

void ShaderTranslator::RemoveDestructionObserver(
    DestructionObserver* observer) {
  destruction_observers_.RemoveObserver(observer);
}

ShaderTranslator::~ShaderTranslator() {
  FOR_EACH_OBSERVER(DestructionObserver,
                    destruction_observers_,
                    OnDestruct(this));

  if (compiler_ != NULL)
    ShDestruct(compiler_);
}

void ShaderTranslator::ClearResults() {
  translated_shader_.reset();
  info_log_.reset();
  attrib_map_.clear();
  uniform_map_.clear();
  varying_map_.clear();
  name_map_.clear();
}

}  // namespace gles2
}  // namespace gpu


/* [<][>][^][v][top][bottom][index][help] */