| // Copyright 2012 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "gpu/command_buffer/service/shader_translator.h" | |
| #include <stddef.h> | |
| #include <string.h> | |
| #include <algorithm> | |
| #include "base/at_exit.h" | |
| #include "base/check.h" | |
| #include "base/command_line.h" | |
| #include "base/lazy_instance.h" | |
| #include "base/observer_list.h" | |
| #include "base/strings/string_number_conversions.h" | |
| #include "base/trace_event/trace_event.h" | |
| #include "ui/gl/gl_bindings.h" | |
| #include "ui/gl/gl_implementation.h" | |
| namespace gpu { | |
| namespace gles2 { | |
| namespace { | |
| class ShaderTranslatorInitializer { | |
| public: | |
| ShaderTranslatorInitializer() { | |
| TRACE_EVENT0("gpu", "ShInitialize"); | |
| CHECK(sh::Initialize()); | |
| } | |
| ~ShaderTranslatorInitializer() { | |
| TRACE_EVENT0("gpu", "ShFinalize"); | |
| sh::Finalize(); | |
| } | |
| }; | |
| base::LazyInstance<ShaderTranslatorInitializer>::DestructorAtExit | |
| g_translator_initializer = LAZY_INSTANCE_INITIALIZER; | |
| void GetAttributes(ShHandle compiler, AttributeMap* var_map) { | |
| if (!var_map) | |
| return; | |
| var_map->clear(); | |
| const std::vector<sh::Attribute>* attribs = sh::GetAttributes(compiler); | |
| if (attribs) { | |
| for (size_t ii = 0; ii < attribs->size(); ++ii) | |
| (*var_map)[(*attribs)[ii].mappedName] = (*attribs)[ii]; | |
| } | |
| } | |
| void GetUniforms(ShHandle compiler, UniformMap* var_map) { | |
| if (!var_map) | |
| return; | |
| var_map->clear(); | |
| const std::vector<sh::Uniform>* uniforms = sh::GetUniforms(compiler); | |
| if (uniforms) { | |
| for (size_t ii = 0; ii < uniforms->size(); ++ii) | |
| (*var_map)[(*uniforms)[ii].mappedName] = (*uniforms)[ii]; | |
| } | |
| } | |
| void GetVaryings(ShHandle compiler, VaryingMap* var_map) { | |
| if (!var_map) | |
| return; | |
| var_map->clear(); | |
| const std::vector<sh::Varying>* varyings = sh::GetVaryings(compiler); | |
| if (varyings) { | |
| for (size_t ii = 0; ii < varyings->size(); ++ii) | |
| (*var_map)[(*varyings)[ii].mappedName] = (*varyings)[ii]; | |
| } | |
| } | |
| void GetOutputVariables(ShHandle compiler, OutputVariableList* var_list) { | |
| if (!var_list) | |
| return; | |
| *var_list = *sh::GetOutputVariables(compiler); | |
| } | |
| void GetInterfaceBlocks(ShHandle compiler, InterfaceBlockMap* var_map) { | |
| if (!var_map) | |
| return; | |
| var_map->clear(); | |
| const std::vector<sh::InterfaceBlock>* interface_blocks = | |
| sh::GetInterfaceBlocks(compiler); | |
| if (interface_blocks) { | |
| for (const auto& block : *interface_blocks) { | |
| (*var_map)[block.mappedName] = block; | |
| } | |
| } | |
| } | |
| } // namespace | |
| ShaderTranslator::DestructionObserver::DestructionObserver() = default; | |
| ShaderTranslator::DestructionObserver::~DestructionObserver() = default; | |
| ShaderTranslator::ShaderTranslator() : compiler_(nullptr), compile_options_{} {} | |
| bool ShaderTranslator::Init(GLenum shader_type, | |
| ShShaderSpec shader_spec, | |
| const ShBuiltInResources* resources, | |
| ShShaderOutput shader_output_language, | |
| const ShCompileOptions& driver_bug_workarounds, | |
| bool gl_shader_interm_output) { | |
| // Make sure Init is called only once. | |
| DCHECK(compiler_ == nullptr); | |
| DCHECK(shader_type == GL_FRAGMENT_SHADER || shader_type == GL_VERTEX_SHADER); | |
| DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC || | |
| shader_spec == SH_GLES3_SPEC || shader_spec == SH_WEBGL2_SPEC); | |
| DCHECK(resources != nullptr); | |
| g_translator_initializer.Get(); | |
| { | |
| TRACE_EVENT0("gpu", "ShConstructCompiler"); | |
| compiler_ = sh::ConstructCompiler(shader_type, shader_spec, | |
| shader_output_language, resources); | |
| } | |
| compile_options_ = driver_bug_workarounds; | |
| compile_options_.objectCode = true; | |
| compile_options_.limitExpressionComplexity = true; | |
| compile_options_.limitCallStackDepth = true; | |
| compile_options_.clampIndirectArrayBounds = true; | |
| compile_options_.emulateGLDrawID = true; | |
| compile_options_.emulateGLBaseVertexBaseInstance = true; | |
| compile_options_.initOutputVariables = true; | |
| std::string compile_options_string = | |
| "objectCode:" | |
| "limitExpressionComplexity:limitCallStackDepth:clampIndirectArrayBounds:" | |
| "emulateGLDrawID:emulateGLBaseVertexBaseInstance:initOutputVariables"; | |
| if (gl_shader_interm_output) { | |
| compile_options_.intermediateTree = true; | |
| compile_options_string += ":intermediateTree"; | |
| } | |
| // Build the options string for additional features that may be set by the | |
| // caller. Note that this code is used by the validating command decoder, | |
| // which is deprecated. No new features are expected to be enabled, neither | |
| // is it expected for there to be new users of this code. | |
| if (compile_options_.initGLPosition) | |
| compile_options_string += ":initGLPosition"; | |
| if (compile_options_.unfoldShortCircuit) | |
| compile_options_string += ":unfoldShortCircuit"; | |
| if (compile_options_.scalarizeVecAndMatConstructorArgs) | |
| compile_options_string += ":scalarizeVecAndMatConstructorArgs"; | |
| if (compile_options_.regenerateStructNames) | |
| compile_options_string += ":regenerateStructNames"; | |
| if (compile_options_.emulateAbsIntFunction) | |
| compile_options_string += ":emulateAbsIntFunction"; | |
| if (compile_options_.rewriteTexelFetchOffsetToTexelFetch) | |
| compile_options_string += ":rewriteTexelFetchOffsetToTexelFetch"; | |
| if (compile_options_.addAndTrueToLoopCondition) | |
| compile_options_string += ":addAndTrueToLoopCondition"; | |
| if (compile_options_.emulateIsnanFloatFunction) | |
| compile_options_string += ":emulateIsnanFloatFunction"; | |
| if (compile_options_.useUnusedStandardSharedBlocks) | |
| compile_options_string += ":useUnusedStandardSharedBlocks"; | |
| if (compile_options_.removeInvariantAndCentroidForESSL3) | |
| compile_options_string += ":removeInvariantAndCentroidForESSL3"; | |
| if (compile_options_.dontUseLoopsToInitializeVariables) | |
| compile_options_string += ":dontUseLoopsToInitializeVariables"; | |
| if (compile_options_.removeDynamicIndexingOfSwizzledVector) | |
| compile_options_string += ":removeDynamicIndexingOfSwizzledVector"; | |
| if (compile_options_.initializeUninitializedLocals) | |
| compile_options_string += ":initializeUninitializedLocals"; | |
| if (compiler_) { | |
| options_affecting_compilation_ = | |
| base::MakeRefCounted<OptionsAffectingCompilationString>( | |
| ":CompileOptions:" + compile_options_string + | |
| sh::GetBuiltInResourcesString(compiler_)); | |
| } | |
| return compiler_ != nullptr; | |
| } | |
| const ShCompileOptions& ShaderTranslator::GetCompileOptions() const { | |
| return compile_options_; | |
| } | |
| bool ShaderTranslator::Translate( | |
| const std::string& shader_source, | |
| std::string* info_log, | |
| std::string* translated_source, | |
| int* shader_version, | |
| AttributeMap* attrib_map, | |
| UniformMap* uniform_map, | |
| VaryingMap* varying_map, | |
| InterfaceBlockMap* interface_block_map, | |
| OutputVariableList* output_variable_list) const { | |
| // Make sure this instance is initialized. | |
| DCHECK(compiler_ != nullptr); | |
| bool success = false; | |
| { | |
| TRACE_EVENT0("gpu", "ShCompile"); | |
| const char* const shader_strings[] = { shader_source.c_str() }; | |
| success = sh::Compile(compiler_, shader_strings, 1, GetCompileOptions()); | |
| } | |
| if (success) { | |
| // Get translated shader. | |
| if (translated_source) { | |
| *translated_source = sh::GetObjectCode(compiler_); | |
| } | |
| // Get shader version. | |
| *shader_version = sh::GetShaderVersion(compiler_); | |
| // Get info for attribs, uniforms, varyings and output variables. | |
| GetAttributes(compiler_, attrib_map); | |
| GetUniforms(compiler_, uniform_map); | |
| GetVaryings(compiler_, varying_map); | |
| GetInterfaceBlocks(compiler_, interface_block_map); | |
| GetOutputVariables(compiler_, output_variable_list); | |
| } | |
| // Get info log. | |
| if (info_log) { | |
| *info_log = sh::GetInfoLog(compiler_); | |
| } | |
| // We don't need results in the compiler anymore. | |
| sh::ClearResults(compiler_); | |
| return success; | |
| } | |
| OptionsAffectingCompilationString* | |
| ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation() const { | |
| return options_affecting_compilation_.get(); | |
| } | |
| void ShaderTranslator::AddDestructionObserver( | |
| DestructionObserver* observer) { | |
| destruction_observers_.AddObserver(observer); | |
| } | |
| void ShaderTranslator::RemoveDestructionObserver( | |
| DestructionObserver* observer) { | |
| destruction_observers_.RemoveObserver(observer); | |
| } | |
| ShaderTranslator::~ShaderTranslator() { | |
| for (auto& observer : destruction_observers_) | |
| observer.OnDestruct(this); | |
| if (compiler_ != nullptr) | |
| sh::Destruct(compiler_); | |
| } | |
| } // namespace gles2 | |
| } // namespace gpu |