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 <GLES2/gl2.h> 9#include <algorithm> 10 11#include "base/at_exit.h" 12#include "base/debug/trace_event.h" 13#include "base/lazy_instance.h" 14#include "base/logging.h" 15#include "base/strings/string_number_conversions.h" 16 17namespace { 18 19using gpu::gles2::ShaderTranslator; 20 21class ShaderTranslatorInitializer { 22 public: 23 ShaderTranslatorInitializer() { 24 TRACE_EVENT0("gpu", "ShInitialize"); 25 CHECK(ShInitialize()); 26 } 27 28 ~ShaderTranslatorInitializer() { 29 TRACE_EVENT0("gpu", "ShFinalize"); 30 ShFinalize(); 31 } 32}; 33 34base::LazyInstance<ShaderTranslatorInitializer> g_translator_initializer = 35 LAZY_INSTANCE_INITIALIZER; 36 37void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type, 38 ShaderTranslator::VariableMap* var_map) { 39 if (!var_map) 40 return; 41 var_map->clear(); 42 43 size_t 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 size_t num_vars = 0; 62 ShGetInfo(compiler, var_type, &num_vars); 63 for (size_t i = 0; i < num_vars; ++i) { 64 size_t len = 0; 65 int size = 0; 66 sh::GLenum type = GL_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 87void GetNameHashingInfo( 88 ShHandle compiler, ShaderTranslator::NameMap* name_map) { 89 if (!name_map) 90 return; 91 name_map->clear(); 92 93 size_t hashed_names_count = 0; 94 ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count); 95 if (hashed_names_count == 0) 96 return; 97 98 size_t name_max_len = 0, hashed_name_max_len = 0; 99 ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len); 100 ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len); 101 102 scoped_ptr<char[]> name(new char[name_max_len]); 103 scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]); 104 105 for (size_t i = 0; i < hashed_names_count; ++i) { 106 ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get()); 107 (*name_map)[hashed_name.get()] = name.get(); 108 } 109} 110 111} // namespace 112 113namespace gpu { 114namespace gles2 { 115 116ShaderTranslator::DestructionObserver::DestructionObserver() { 117} 118 119ShaderTranslator::DestructionObserver::~DestructionObserver() { 120} 121 122ShaderTranslator::ShaderTranslator() 123 : compiler_(NULL), 124 implementation_is_glsl_es_(false), 125 driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) { 126} 127 128bool ShaderTranslator::Init( 129 GLenum shader_type, 130 ShShaderSpec shader_spec, 131 const ShBuiltInResources* resources, 132 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type, 133 ShCompileOptions driver_bug_workarounds) { 134 // Make sure Init is called only once. 135 DCHECK(compiler_ == NULL); 136 DCHECK(shader_type == GL_FRAGMENT_SHADER || shader_type == GL_VERTEX_SHADER); 137 DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC); 138 DCHECK(resources != NULL); 139 140 g_translator_initializer.Get(); 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 driver_bug_workarounds_ = driver_bug_workarounds; 153 return compiler_ != NULL; 154} 155 156int ShaderTranslator::GetCompileOptions() const { 157 int compile_options = 158 SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS | 159 SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH | 160 SH_CLAMP_INDIRECT_ARRAY_BOUNDS; 161 162 compile_options |= driver_bug_workarounds_; 163 164 return compile_options; 165} 166 167bool ShaderTranslator::Translate(const std::string& shader_source, 168 std::string* info_log, 169 std::string* translated_source, 170 VariableMap* attrib_map, 171 VariableMap* uniform_map, 172 VariableMap* varying_map, 173 NameMap* name_map) const { 174 // Make sure this instance is initialized. 175 DCHECK(compiler_ != NULL); 176 177 bool success = false; 178 { 179 TRACE_EVENT0("gpu", "ShCompile"); 180 const char* const shader_strings[] = { shader_source.c_str() }; 181 success = !!ShCompile( 182 compiler_, shader_strings, 1, GetCompileOptions()); 183 } 184 if (success) { 185 if (translated_source) { 186 translated_source->clear(); 187 // Get translated shader. 188 size_t obj_code_len = 0; 189 ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len); 190 if (obj_code_len > 1) { 191 scoped_ptr<char[]> buffer(new char[obj_code_len]); 192 ShGetObjectCode(compiler_, buffer.get()); 193 *translated_source = std::string(buffer.get(), obj_code_len - 1); 194 } 195 } 196 // Get info for attribs, uniforms, and varyings. 197 GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, attrib_map); 198 GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, uniform_map); 199 GetVariableInfo(compiler_, SH_VARYINGS, varying_map); 200 // Get info for name hashing. 201 GetNameHashingInfo(compiler_, name_map); 202 } 203 204 // Get info log. 205 if (info_log) { 206 info_log->clear(); 207 size_t info_log_len = 0; 208 ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len); 209 if (info_log_len > 1) { 210 scoped_ptr<char[]> buffer(new char[info_log_len]); 211 ShGetInfoLog(compiler_, buffer.get()); 212 *info_log = std::string(buffer.get(), info_log_len - 1); 213 } 214 } 215 216 return success; 217} 218 219std::string ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation() 220 const { 221 DCHECK(compiler_ != NULL); 222 223 size_t resource_len = 0; 224 ShGetInfo(compiler_, SH_RESOURCES_STRING_LENGTH, &resource_len); 225 DCHECK(resource_len > 1); 226 scoped_ptr<char[]> resource_str(new char[resource_len]); 227 228 ShGetBuiltInResourcesString(compiler_, resource_len, resource_str.get()); 229 230 return std::string(":CompileOptions:" + 231 base::IntToString(GetCompileOptions())) + 232 std::string(resource_str.get()); 233} 234 235void ShaderTranslator::AddDestructionObserver( 236 DestructionObserver* observer) { 237 destruction_observers_.AddObserver(observer); 238} 239 240void ShaderTranslator::RemoveDestructionObserver( 241 DestructionObserver* observer) { 242 destruction_observers_.RemoveObserver(observer); 243} 244 245ShaderTranslator::~ShaderTranslator() { 246 FOR_EACH_OBSERVER(DestructionObserver, 247 destruction_observers_, 248 OnDestruct(this)); 249 250 if (compiler_ != NULL) 251 ShDestruct(compiler_); 252} 253 254} // namespace gles2 255} // namespace gpu 256 257