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 default: NOTREACHED(); 52 } 53 ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len); 54 if (name_len <= 1 || mapped_name_len <= 1) return; 55 scoped_ptr<char[]> name(new char[name_len]); 56 scoped_ptr<char[]> mapped_name(new char[mapped_name_len]); 57 58 ANGLEGetInfoType num_vars = 0; 59 ShGetInfo(compiler, var_type, &num_vars); 60 for (ANGLEGetInfoType i = 0; i < num_vars; ++i) { 61 ANGLEGetInfoType len = 0; 62 int size = 0; 63 ShDataType type = SH_NONE; 64 65 switch (var_type) { 66 case SH_ACTIVE_ATTRIBUTES: 67 ShGetActiveAttrib( 68 compiler, i, &len, &size, &type, name.get(), mapped_name.get()); 69 break; 70 case SH_ACTIVE_UNIFORMS: 71 ShGetActiveUniform( 72 compiler, i, &len, &size, &type, name.get(), mapped_name.get()); 73 break; 74 default: NOTREACHED(); 75 } 76 77 // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs 78 // to handle long struct field name mapping before we can do this. 79 // Also, we should modify the ANGLE interface to also return a length 80 // for mapped_name. 81 std::string name_string(name.get(), std::min(len, name_len - 1)); 82 mapped_name.get()[mapped_name_len - 1] = '\0'; 83 84 ShaderTranslator::VariableInfo info(type, size, name_string); 85 (*var_map)[mapped_name.get()] = info; 86 } 87 } 88 89 void 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 111 namespace gpu { 112 namespace gles2 { 113 114 ShaderTranslator::DestructionObserver::DestructionObserver() { 115 } 116 117 ShaderTranslator::DestructionObserver::~DestructionObserver() { 118 } 119 120 ShaderTranslator::ShaderTranslator() 121 : compiler_(NULL), 122 implementation_is_glsl_es_(false), 123 needs_built_in_function_emulation_(false) { 124 } 125 126 bool ShaderTranslator::Init( 127 ShShaderType shader_type, 128 ShShaderSpec shader_spec, 129 const ShBuiltInResources* resources, 130 ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type, 131 ShaderTranslatorInterface::GlslBuiltInFunctionBehavior 132 glsl_built_in_function_behavior) { 133 // Make sure Init is called only once. 134 DCHECK(compiler_ == NULL); 135 DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER); 136 DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC); 137 DCHECK(resources != NULL); 138 139 if (!InitializeShaderTranslator()) 140 return false; 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 needs_built_in_function_emulation_ = 153 (glsl_built_in_function_behavior == kGlslBuiltInFunctionEmulated); 154 return compiler_ != NULL; 155 } 156 157 int ShaderTranslator::GetCompileOptions() const { 158 int compile_options = 159 SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS | 160 SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS | 161 SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH; 162 163 compile_options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS; 164 165 if (needs_built_in_function_emulation_) 166 compile_options |= SH_EMULATE_BUILT_IN_FUNCTIONS; 167 168 return compile_options; 169 } 170 171 bool ShaderTranslator::Translate(const char* shader) { 172 // Make sure this instance is initialized. 173 DCHECK(compiler_ != NULL); 174 DCHECK(shader != NULL); 175 ClearResults(); 176 177 bool success = false; 178 { 179 TRACE_EVENT0("gpu", "ShCompile"); 180 success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions()); 181 } 182 if (success) { 183 // Get translated shader. 184 ANGLEGetInfoType obj_code_len = 0; 185 ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len); 186 if (obj_code_len > 1) { 187 translated_shader_.reset(new char[obj_code_len]); 188 ShGetObjectCode(compiler_, translated_shader_.get()); 189 } 190 // Get info for attribs and uniforms. 191 GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_); 192 GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_); 193 // Get info for name hashing. 194 GetNameHashingInfo(compiler_, &name_map_); 195 } 196 197 // Get info log. 198 ANGLEGetInfoType info_log_len = 0; 199 ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len); 200 if (info_log_len > 1) { 201 info_log_.reset(new char[info_log_len]); 202 ShGetInfoLog(compiler_, info_log_.get()); 203 } else { 204 info_log_.reset(); 205 } 206 207 return success; 208 } 209 210 std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation() 211 const { 212 const size_t kNumIntFields = 16; 213 const size_t kNumEnumFields = 1; 214 const size_t kNumFunctionPointerFields = 1; 215 struct MustMatchShBuiltInResource { 216 typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t); 217 enum Enum { 218 kFirst, 219 }; 220 int int_fields[kNumIntFields]; 221 FunctionPointer pointer_fields[kNumFunctionPointerFields]; 222 Enum enum_fields[kNumEnumFields]; 223 }; 224 // If this assert fails most likely that means something below needs updating. 225 COMPILE_ASSERT( 226 sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource), 227 Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below); 228 229 return std::string( 230 ":CompileOptions:" + 231 base::IntToString(GetCompileOptions()) + 232 ":MaxVertexAttribs:" + 233 base::IntToString(compiler_options_.MaxVertexAttribs) + 234 ":MaxVertexUniformVectors:" + 235 base::IntToString(compiler_options_.MaxVertexUniformVectors) + 236 ":MaxVaryingVectors:" + 237 base::IntToString(compiler_options_.MaxVaryingVectors) + 238 ":MaxVertexTextureImageUnits:" + 239 base::IntToString(compiler_options_.MaxVertexTextureImageUnits) + 240 ":MaxCombinedTextureImageUnits:" + 241 base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) + 242 ":MaxTextureImageUnits:" + 243 base::IntToString(compiler_options_.MaxTextureImageUnits) + 244 ":MaxFragmentUniformVectors:" + 245 base::IntToString(compiler_options_.MaxFragmentUniformVectors) + 246 ":MaxDrawBuffers:" + 247 base::IntToString(compiler_options_.MaxDrawBuffers) + 248 ":OES_standard_derivatives:" + 249 base::IntToString(compiler_options_.OES_standard_derivatives) + 250 ":OES_EGL_image_external:" + 251 base::IntToString(compiler_options_.OES_EGL_image_external) + 252 ":ARB_texture_rectangle:" + 253 base::IntToString(compiler_options_.ARB_texture_rectangle) + 254 ":EXT_draw_buffers:" + 255 base::IntToString(compiler_options_.EXT_draw_buffers) + 256 ":FragmentPrecisionHigh:" + 257 base::IntToString(compiler_options_.FragmentPrecisionHigh) + 258 ":MaxExpressionComplexity:" + 259 base::IntToString(compiler_options_.MaxExpressionComplexity) + 260 ":MaxCallStackDepth:" + 261 base::IntToString(compiler_options_.MaxCallStackDepth) + 262 ":EXT_frag_depth:" + 263 base::IntToString(compiler_options_.EXT_frag_depth)); 264 } 265 266 const char* ShaderTranslator::translated_shader() const { 267 return translated_shader_.get(); 268 } 269 270 const char* ShaderTranslator::info_log() const { 271 return info_log_.get(); 272 } 273 274 const ShaderTranslatorInterface::VariableMap& 275 ShaderTranslator::attrib_map() const { 276 return attrib_map_; 277 } 278 279 const ShaderTranslatorInterface::VariableMap& 280 ShaderTranslator::uniform_map() const { 281 return uniform_map_; 282 } 283 284 const ShaderTranslatorInterface::NameMap& 285 ShaderTranslator::name_map() const { 286 return name_map_; 287 } 288 289 void ShaderTranslator::AddDestructionObserver( 290 DestructionObserver* observer) { 291 destruction_observers_.AddObserver(observer); 292 } 293 294 void ShaderTranslator::RemoveDestructionObserver( 295 DestructionObserver* observer) { 296 destruction_observers_.RemoveObserver(observer); 297 } 298 299 ShaderTranslator::~ShaderTranslator() { 300 FOR_EACH_OBSERVER(DestructionObserver, 301 destruction_observers_, 302 OnDestruct(this)); 303 304 if (compiler_ != NULL) 305 ShDestruct(compiler_); 306 } 307 308 void ShaderTranslator::ClearResults() { 309 translated_shader_.reset(); 310 info_log_.reset(); 311 attrib_map_.clear(); 312 uniform_map_.clear(); 313 name_map_.clear(); 314 } 315 316 } // namespace gles2 317 } // namespace gpu 318 319