blob: 43b29ef1a4ab17e2a307b26c65a3e914ed892ba3 [file] [log] [blame]
// 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