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