shader_translator.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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 15namespace { 16 17using gpu::gles2::ShaderTranslator; 18 19bool g_translator_initialized = false; 20 21void FinalizeShaderTranslator(void* /* dummy */) { 22 TRACE_EVENT0("gpu", "ShFinalize"); 23 ShFinalize(); 24 g_translator_initialized = false; 25} 26 27bool InitializeShaderTranslator() { 28 if (!g_translator_initialized) { 29 TRACE_EVENT0("gpu", "ShInitialize"); 30 CHECK(ShInitialize()); 31 base::AtExitManager::RegisterCallback(&FinalizeShaderTranslator, NULL); 32 g_translator_initialized = true; 33 } 34 return g_translator_initialized; 35} 36 37#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108 38typedef int ANGLEGetInfoType; 39#else 40typedef size_t ANGLEGetInfoType; 41#endif 42 43void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type, 44 ShaderTranslator::VariableMap* var_map) { 45 ANGLEGetInfoType name_len = 0, mapped_name_len = 0; 46 switch (var_type) { 47 case SH_ACTIVE_ATTRIBUTES: 48 ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len); 49 break; 50 case SH_ACTIVE_UNIFORMS: 51 ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len); 52 break; 53 case SH_VARYINGS: 54 ShGetInfo(compiler, SH_VARYING_MAX_LENGTH, &name_len); 55 break; 56 default: NOTREACHED(); 57 } 58 ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len); 59 if (name_len <= 1 || mapped_name_len <= 1) return; 60 scoped_ptr<char[]> name(new char[name_len]); 61 scoped_ptr<char[]> mapped_name(new char[mapped_name_len]); 62 63 ANGLEGetInfoType num_vars = 0; 64 ShGetInfo(compiler, var_type, &num_vars); 65 for (ANGLEGetInfoType i = 0; i < num_vars; ++i) { 66 ANGLEGetInfoType len = 0; 67 int size = 0; 68 ShDataType type = SH_NONE; 69 ShPrecisionType precision = SH_PRECISION_UNDEFINED; 70 int static_use = 0; 71 72 ShGetVariableInfo(compiler, var_type, i, 73 &len, &size, &type, &precision, &static_use, 74 name.get(), mapped_name.get()); 75 76 // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs 77 // to handle long struct field name mapping before we can do this. 78 // Also, we should modify the ANGLE interface to also return a length 79 // for mapped_name. 80 std::string name_string(name.get(), std::min(len, name_len - 1)); 81 mapped_name.get()[mapped_name_len - 1] = '\0'; 82 83 ShaderTranslator::VariableInfo info( 84 type, size, precision, static_use, name_string); 85 (*var_map)[mapped_name.get()] = info; 86 } 87} 88 89void 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 111namespace gpu { 112namespace gles2 { 113 114ShaderTranslator::DestructionObserver::DestructionObserver() { 115} 116 117ShaderTranslator::DestructionObserver::~DestructionObserver() { 118} 119 120ShaderTranslator::ShaderTranslator() 121 : compiler_(NULL), 122 implementation_is_glsl_es_(false), 123 driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) { 124} 125 126bool ShaderTranslator::Init( 127 ShShaderType shader_type, 128 ShShaderSpec shader_spec, 129 const ShBuiltInResources* resources, 130 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type, 131 ShCompileOptions driver_bug_workarounds) { 132 // Make sure Init is called only once. 133 DCHECK(compiler_ == NULL); 134 DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER); 135 DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC); 136 DCHECK(resources != NULL); 137 138 if (!InitializeShaderTranslator()) 139 return false; 140 141 ShShaderOutput shader_output = 142 (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT); 143 144 { 145 TRACE_EVENT0("gpu", "ShConstructCompiler"); 146 compiler_ = ShConstructCompiler( 147 shader_type, shader_spec, shader_output, resources); 148 } 149 compiler_options_ = *resources; 150 implementation_is_glsl_es_ = (glsl_implementation_type == kGlslES); 151 driver_bug_workarounds_ = driver_bug_workarounds; 152 return compiler_ != NULL; 153} 154 155int ShaderTranslator::GetCompileOptions() const { 156 int compile_options = 157 SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS | 158 SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH | 159 SH_CLAMP_INDIRECT_ARRAY_BOUNDS; 160 161 compile_options |= driver_bug_workarounds_; 162 163 return compile_options; 164} 165 166bool ShaderTranslator::Translate(const char* shader) { 167 // Make sure this instance is initialized. 168 DCHECK(compiler_ != NULL); 169 DCHECK(shader != NULL); 170 ClearResults(); 171 172 bool success = false; 173 { 174 TRACE_EVENT0("gpu", "ShCompile"); 175 success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions()); 176 } 177 if (success) { 178 // Get translated shader. 179 ANGLEGetInfoType obj_code_len = 0; 180 ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len); 181 if (obj_code_len > 1) { 182 translated_shader_.reset(new char[obj_code_len]); 183 ShGetObjectCode(compiler_, translated_shader_.get()); 184 } 185 // Get info for attribs and uniforms. 186 GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_); 187 GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_); 188 GetVariableInfo(compiler_, SH_VARYINGS, &varying_map_); 189 // Get info for name hashing. 190 GetNameHashingInfo(compiler_, &name_map_); 191 } 192 193 // Get info log. 194 ANGLEGetInfoType info_log_len = 0; 195 ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len); 196 if (info_log_len > 1) { 197 info_log_.reset(new char[info_log_len]); 198 ShGetInfoLog(compiler_, info_log_.get()); 199 } else { 200 info_log_.reset(); 201 } 202 203 return success; 204} 205 206std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation() 207 const { 208 209#if ANGLE_SH_VERSION >= 122 210 const size_t kNumIntFields = 20; 211#else 212 const size_t kNumIntFields = 16; 213#endif 214 const size_t kNumEnumFields = 1; 215 const size_t kNumFunctionPointerFields = 1; 216 struct MustMatchShBuiltInResource { 217 typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t); 218 enum Enum { 219 kFirst, 220 }; 221 int int_fields[kNumIntFields]; 222 FunctionPointer pointer_fields[kNumFunctionPointerFields]; 223 Enum enum_fields[kNumEnumFields]; 224 }; 225 // If this assert fails most likely that means something below needs updating. 226 COMPILE_ASSERT( 227 sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource), 228 Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below); 229 230 return std::string( 231 ":CompileOptions:" + 232 base::IntToString(GetCompileOptions()) + 233 ":MaxVertexAttribs:" + 234 base::IntToString(compiler_options_.MaxVertexAttribs) + 235 ":MaxVertexUniformVectors:" + 236 base::IntToString(compiler_options_.MaxVertexUniformVectors) + 237 ":MaxVaryingVectors:" + 238 base::IntToString(compiler_options_.MaxVaryingVectors) + 239 ":MaxVertexTextureImageUnits:" + 240 base::IntToString(compiler_options_.MaxVertexTextureImageUnits) + 241 ":MaxCombinedTextureImageUnits:" + 242 base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) + 243 ":MaxTextureImageUnits:" + 244 base::IntToString(compiler_options_.MaxTextureImageUnits) + 245 ":MaxFragmentUniformVectors:" + 246 base::IntToString(compiler_options_.MaxFragmentUniformVectors) + 247 ":MaxDrawBuffers:" + 248 base::IntToString(compiler_options_.MaxDrawBuffers) + 249 ":OES_standard_derivatives:" + 250 base::IntToString(compiler_options_.OES_standard_derivatives) + 251 ":OES_EGL_image_external:" + 252 base::IntToString(compiler_options_.OES_EGL_image_external) + 253 ":ARB_texture_rectangle:" + 254 base::IntToString(compiler_options_.ARB_texture_rectangle) + 255 ":EXT_draw_buffers:" + 256 base::IntToString(compiler_options_.EXT_draw_buffers) + 257 ":FragmentPrecisionHigh:" + 258 base::IntToString(compiler_options_.FragmentPrecisionHigh) + 259 ":MaxExpressionComplexity:" + 260 base::IntToString(compiler_options_.MaxExpressionComplexity) + 261 ":MaxCallStackDepth:" + 262 base::IntToString(compiler_options_.MaxCallStackDepth) + 263 ":EXT_frag_depth:" + 264#if ANGLE_SH_VERSION >= 122 265 base::IntToString(compiler_options_.EXT_frag_depth) + 266 ":MaxVertexOutputVectors:" + 267 base::IntToString(compiler_options_.MaxVertexOutputVectors) + 268 ":MaxFragmentInputVectors:" + 269 base::IntToString(compiler_options_.MaxFragmentInputVectors) + 270 ":MinProgramTexelOffset:" + 271 base::IntToString(compiler_options_.MinProgramTexelOffset) + 272 ":MaxProgramTexelOffset:" + 273 base::IntToString(compiler_options_.MaxProgramTexelOffset)); 274#else 275 base::IntToString(compiler_options_.EXT_frag_depth)); 276#endif 277} 278 279const char* ShaderTranslator::translated_shader() const { 280 return translated_shader_.get(); 281} 282 283const char* ShaderTranslator::info_log() const { 284 return info_log_.get(); 285} 286 287const ShaderTranslatorInterface::VariableMap& 288ShaderTranslator::attrib_map() const { 289 return attrib_map_; 290} 291 292const ShaderTranslatorInterface::VariableMap& 293ShaderTranslator::uniform_map() const { 294 return uniform_map_; 295} 296 297const ShaderTranslatorInterface::VariableMap& 298ShaderTranslator::varying_map() const { 299 return varying_map_; 300} 301 302const ShaderTranslatorInterface::NameMap& 303ShaderTranslator::name_map() const { 304 return name_map_; 305} 306 307void ShaderTranslator::AddDestructionObserver( 308 DestructionObserver* observer) { 309 destruction_observers_.AddObserver(observer); 310} 311 312void ShaderTranslator::RemoveDestructionObserver( 313 DestructionObserver* observer) { 314 destruction_observers_.RemoveObserver(observer); 315} 316 317ShaderTranslator::~ShaderTranslator() { 318 FOR_EACH_OBSERVER(DestructionObserver, 319 destruction_observers_, 320 OnDestruct(this)); 321 322 if (compiler_ != NULL) 323 ShDestruct(compiler_); 324} 325 326void ShaderTranslator::ClearResults() { 327 translated_shader_.reset(); 328 info_log_.reset(); 329 attrib_map_.clear(); 330 uniform_map_.clear(); 331 varying_map_.clear(); 332 name_map_.clear(); 333} 334 335} // namespace gles2 336} // namespace gpu 337 338