| // Copyright (c) 2010 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 "base/at_exit.h" |
| #include "base/logging.h" |
| |
| namespace { |
| void FinalizeShaderTranslator(void* /* dummy */) { |
| ShFinalize(); |
| } |
| |
| bool InitializeShaderTranslator() { |
| static bool initialized = false; |
| if (!initialized && ShInitialize()) { |
| base::AtExitManager::RegisterCallback(&FinalizeShaderTranslator, NULL); |
| initialized = true; |
| } |
| return initialized; |
| } |
| |
| using gpu::gles2::ShaderTranslator; |
| void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type, |
| ShaderTranslator::VariableMap* var_map) { |
| int 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; |
| default: NOTREACHED(); |
| } |
| if (name_len <= 1) return; |
| scoped_array<char> name(new char[name_len]); |
| |
| int num_vars = 0; |
| ShGetInfo(compiler, var_type, &num_vars); |
| for (int i = 0; i < num_vars; ++i) { |
| int size = 0; |
| ShDataType type = SH_NONE; |
| |
| switch (var_type) { |
| case SH_ACTIVE_ATTRIBUTES: |
| ShGetActiveAttrib(compiler, i, NULL, &size, &type, name.get()); |
| break; |
| case SH_ACTIVE_UNIFORMS: |
| ShGetActiveUniform(compiler, i, NULL, &size, &type, name.get()); |
| break; |
| default: NOTREACHED(); |
| } |
| |
| ShaderTranslator::VariableInfo info(type, size); |
| (*var_map)[name.get()] = info; |
| } |
| } |
| } // namespace |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| ShaderTranslator::ShaderTranslator() |
| : compiler_(NULL), |
| implementation_is_glsl_es_(false) { |
| } |
| |
| ShaderTranslator::~ShaderTranslator() { |
| if (compiler_ != NULL) |
| ShDestruct(compiler_); |
| } |
| |
| bool ShaderTranslator::Init(ShShaderType shader_type, |
| ShShaderSpec shader_spec, |
| const ShBuiltInResources* resources, |
| bool implementation_is_glsl_es) { |
| // 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); |
| |
| if (!InitializeShaderTranslator()) |
| return false; |
| |
| compiler_ = ShConstructCompiler(shader_type, shader_spec, resources); |
| implementation_is_glsl_es_ = implementation_is_glsl_es; |
| return compiler_ != NULL; |
| } |
| |
| bool ShaderTranslator::Translate(const char* shader) { |
| // Make sure this instance is initialized. |
| DCHECK(compiler_ != NULL); |
| DCHECK(shader != NULL); |
| ClearResults(); |
| |
| bool success = false; |
| int compile_options = SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS; |
| if (ShCompile(compiler_, &shader, 1, compile_options)) { |
| success = true; |
| if (!implementation_is_glsl_es_) { |
| // Get translated shader. |
| int 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()); |
| } |
| } else { |
| // Pass down the original shader's source rather than the |
| // compiler's output. TODO(kbr): once the shader compiler has a |
| // GLSL ES backend, use its output. |
| int shader_code_len = 1 + strlen(shader); |
| if (shader_code_len > 1) { |
| translated_shader_.reset(new char[shader_code_len]); |
| strncpy(translated_shader_.get(), shader, shader_code_len); |
| } |
| } |
| // Get info for attribs and uniforms. |
| GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_); |
| GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_); |
| } |
| |
| // Get info log. |
| int 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()); |
| } |
| |
| return success; |
| } |
| |
| 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_; |
| } |
| |
| void ShaderTranslator::ClearResults() { |
| translated_shader_.reset(); |
| info_log_.reset(); |
| attrib_map_.clear(); |
| uniform_map_.clear(); |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |
| |