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 15 namespace { 16 17 using gpu::gles2::ShaderTranslator; 18 19 void FinalizeShaderTranslator(void* /* dummy */) { 20 TRACE_EVENT0("gpu", "ShFinalize"); 21 ShFinalize(); 22 } 23 24 bool InitializeShaderTranslator() { 25 static bool initialized = false; 26 if (!initialized) { 27 TRACE_EVENT0("gpu", "ShInitialize"); 28 CHECK(ShInitialize()); 29 base::AtExitManager::RegisterCallback(&FinalizeShaderTranslator, NULL); 30 initialized = true; 31 } 32 return initialized; 33 } 34 35 #if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108 36 typedef int ANGLEGetInfoType; 37 #else 38 typedef size_t ANGLEGetInfoType; 39 #endif 40 41 void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type, 42 ShaderTranslator::VariableMap* var_map) { 43 ANGLEGetInfoType 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 ANGLEGetInfoType num_vars = 0; 62 ShGetInfo(compiler, var_type, &num_vars); 63 for (ANGLEGetInfoType i = 0; i < num_vars; ++i) { 64 ANGLEGetInfoType len = 0; 65 int size = 0; 66 ShDataType type = SH_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 87 void GetNameHashingInfo( 88 ShHandle compiler, ShaderTranslator::NameMap* name_map) { 89 ANGLEGetInfoType hashed_names_count = 0; 90 ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count); 91 if (hashed_names_count == 0) 92 return; 93 94 ANGLEGetInfoType name_max_len = 0, hashed_name_max_len = 0; 95 ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len); 96 ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len); 97 98 scoped_ptr<char[]> name(new char[name_max_len]); 99 scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]); 100 101 for (ANGLEGetInfoType i = 0; i < hashed_names_count; ++i) { 102 ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get()); 103 (*name_map)[hashed_name.get()] = name.get(); 104 } 105 } 106 107 } // namespace 108 109 namespace gpu { 110 namespace gles2 { 111 112 ShaderTranslator::DestructionObserver::DestructionObserver() { 113 } 114 115 ShaderTranslator::DestructionObserver::~DestructionObserver() { 116 } 117 118 ShaderTranslator::ShaderTranslator() 119 : compiler_(NULL), 120 implementation_is_glsl_es_(false), 121 driver_bug_workarounds_(static_cast<ShCompileOptions>(0)) { 122 } 123 124 bool ShaderTranslator::Init( 125 ShShaderType shader_type, 126 ShShaderSpec shader_spec, 127 const ShBuiltInResources* resources, 128 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type, 129 ShCompileOptions driver_bug_workarounds) { 130 // Make sure Init is called only once. 131 DCHECK(compiler_ == NULL); 132 DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER); 133 DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC); 134 DCHECK(resources != NULL); 135 136 if (!InitializeShaderTranslator()) 137 return false; 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 | 156 SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS | 157 SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH; 158 159 compile_options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS; 160 161 compile_options |= driver_bug_workarounds_; 162 163 return compile_options; 164 } 165 166 bool 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 206 std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation() 207 const { 208 const size_t kNumIntFields = 16; 209 const size_t kNumEnumFields = 1; 210 const size_t kNumFunctionPointerFields = 1; 211 struct MustMatchShBuiltInResource { 212 typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t); 213 enum Enum { 214 kFirst, 215 }; 216 int int_fields[kNumIntFields]; 217 FunctionPointer pointer_fields[kNumFunctionPointerFields]; 218 Enum enum_fields[kNumEnumFields]; 219 }; 220 // If this assert fails most likely that means something below needs updating. 221 COMPILE_ASSERT( 222 sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource), 223 Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below); 224 225 return std::string( 226 ":CompileOptions:" + 227 base::IntToString(GetCompileOptions()) + 228 ":MaxVertexAttribs:" + 229 base::IntToString(compiler_options_.MaxVertexAttribs) + 230 ":MaxVertexUniformVectors:" + 231 base::IntToString(compiler_options_.MaxVertexUniformVectors) + 232 ":MaxVaryingVectors:" + 233 base::IntToString(compiler_options_.MaxVaryingVectors) + 234 ":MaxVertexTextureImageUnits:" + 235 base::IntToString(compiler_options_.MaxVertexTextureImageUnits) + 236 ":MaxCombinedTextureImageUnits:" + 237 base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) + 238 ":MaxTextureImageUnits:" + 239 base::IntToString(compiler_options_.MaxTextureImageUnits) + 240 ":MaxFragmentUniformVectors:" + 241 base::IntToString(compiler_options_.MaxFragmentUniformVectors) + 242 ":MaxDrawBuffers:" + 243 base::IntToString(compiler_options_.MaxDrawBuffers) + 244 ":OES_standard_derivatives:" + 245 base::IntToString(compiler_options_.OES_standard_derivatives) + 246 ":OES_EGL_image_external:" + 247 base::IntToString(compiler_options_.OES_EGL_image_external) + 248 ":ARB_texture_rectangle:" + 249 base::IntToString(compiler_options_.ARB_texture_rectangle) + 250 ":EXT_draw_buffers:" + 251 base::IntToString(compiler_options_.EXT_draw_buffers) + 252 ":FragmentPrecisionHigh:" + 253 base::IntToString(compiler_options_.FragmentPrecisionHigh) + 254 ":MaxExpressionComplexity:" + 255 base::IntToString(compiler_options_.MaxExpressionComplexity) + 256 ":MaxCallStackDepth:" + 257 base::IntToString(compiler_options_.MaxCallStackDepth) + 258 ":EXT_frag_depth:" + 259 base::IntToString(compiler_options_.EXT_frag_depth)); 260 } 261 262 const char* ShaderTranslator::translated_shader() const { 263 return translated_shader_.get(); 264 } 265 266 const char* ShaderTranslator::info_log() const { 267 return info_log_.get(); 268 } 269 270 const ShaderTranslatorInterface::VariableMap& 271 ShaderTranslator::attrib_map() const { 272 return attrib_map_; 273 } 274 275 const ShaderTranslatorInterface::VariableMap& 276 ShaderTranslator::uniform_map() const { 277 return uniform_map_; 278 } 279 280 const ShaderTranslatorInterface::VariableMap& 281 ShaderTranslator::varying_map() const { 282 return varying_map_; 283 } 284 285 const ShaderTranslatorInterface::NameMap& 286 ShaderTranslator::name_map() const { 287 return name_map_; 288 } 289 290 void ShaderTranslator::AddDestructionObserver( 291 DestructionObserver* observer) { 292 destruction_observers_.AddObserver(observer); 293 } 294 295 void ShaderTranslator::RemoveDestructionObserver( 296 DestructionObserver* observer) { 297 destruction_observers_.RemoveObserver(observer); 298 } 299 300 ShaderTranslator::~ShaderTranslator() { 301 FOR_EACH_OBSERVER(DestructionObserver, 302 destruction_observers_, 303 OnDestruct(this)); 304 305 if (compiler_ != NULL) 306 ShDestruct(compiler_); 307 } 308 309 void ShaderTranslator::ClearResults() { 310 translated_shader_.reset(); 311 info_log_.reset(); 312 attrib_map_.clear(); 313 uniform_map_.clear(); 314 varying_map_.clear(); 315 name_map_.clear(); 316 } 317 318 } // namespace gles2 319 } // namespace gpu 320 321