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 <stddef.h>
8 #include <string.h>
9 #include <algorithm>
10 
11 #include "base/at_exit.h"
12 #include "base/check.h"
13 #include "base/command_line.h"
14 #include "base/lazy_instance.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/trace_event/trace_event.h"
17 #include "ui/gl/gl_bindings.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/gl_version_info.h"
20 
21 namespace gpu {
22 namespace gles2 {
23 
24 namespace {
25 
26 class ShaderTranslatorInitializer {
27  public:
ShaderTranslatorInitializer()28   ShaderTranslatorInitializer() {
29     TRACE_EVENT0("gpu", "ShInitialize");
30     CHECK(sh::Initialize());
31   }
32 
~ShaderTranslatorInitializer()33   ~ShaderTranslatorInitializer() {
34     TRACE_EVENT0("gpu", "ShFinalize");
35     sh::Finalize();
36   }
37 };
38 
39 base::LazyInstance<ShaderTranslatorInitializer>::DestructorAtExit
40     g_translator_initializer = LAZY_INSTANCE_INITIALIZER;
41 
GetAttributes(ShHandle compiler,AttributeMap * var_map)42 void GetAttributes(ShHandle compiler, AttributeMap* var_map) {
43   if (!var_map)
44     return;
45   var_map->clear();
46   const std::vector<sh::Attribute>* attribs = sh::GetAttributes(compiler);
47   if (attribs) {
48     for (size_t ii = 0; ii < attribs->size(); ++ii)
49       (*var_map)[(*attribs)[ii].mappedName] = (*attribs)[ii];
50   }
51 }
52 
GetUniforms(ShHandle compiler,UniformMap * var_map)53 void GetUniforms(ShHandle compiler, UniformMap* var_map) {
54   if (!var_map)
55     return;
56   var_map->clear();
57   const std::vector<sh::Uniform>* uniforms = sh::GetUniforms(compiler);
58   if (uniforms) {
59     for (size_t ii = 0; ii < uniforms->size(); ++ii)
60       (*var_map)[(*uniforms)[ii].mappedName] = (*uniforms)[ii];
61   }
62 }
63 
GetVaryings(ShHandle compiler,VaryingMap * var_map)64 void GetVaryings(ShHandle compiler, VaryingMap* var_map) {
65   if (!var_map)
66     return;
67   var_map->clear();
68   const std::vector<sh::Varying>* varyings = sh::GetVaryings(compiler);
69   if (varyings) {
70     for (size_t ii = 0; ii < varyings->size(); ++ii)
71       (*var_map)[(*varyings)[ii].mappedName] = (*varyings)[ii];
72   }
73 }
GetOutputVariables(ShHandle compiler,OutputVariableList * var_list)74 void GetOutputVariables(ShHandle compiler, OutputVariableList* var_list) {
75   if (!var_list)
76     return;
77   *var_list = *sh::GetOutputVariables(compiler);
78 }
79 
GetInterfaceBlocks(ShHandle compiler,InterfaceBlockMap * var_map)80 void GetInterfaceBlocks(ShHandle compiler, InterfaceBlockMap* var_map) {
81   if (!var_map)
82     return;
83   var_map->clear();
84   const std::vector<sh::InterfaceBlock>* interface_blocks =
85       sh::GetInterfaceBlocks(compiler);
86   if (interface_blocks) {
87     for (const auto& block : *interface_blocks) {
88       (*var_map)[block.mappedName] = block;
89     }
90   }
91 }
92 
93 }  // namespace
94 
GetShaderOutputLanguageForContext(const gl::GLVersionInfo & version_info)95 ShShaderOutput ShaderTranslator::GetShaderOutputLanguageForContext(
96     const gl::GLVersionInfo& version_info) {
97   if (version_info.is_es) {
98     return SH_ESSL_OUTPUT;
99   }
100 
101   // Determine the GLSL version based on OpenGL specification.
102 
103   unsigned context_version =
104       version_info.major_version * 100 + version_info.minor_version * 10;
105   if (context_version >= 450) {
106     // OpenGL specs from 4.2 on specify that the core profile is "also
107     // guaranteed to support all previous versions of the OpenGL Shading
108     // Language back to version 1.40". For simplicity, we assume future
109     // specs do not unspecify this. If they did, they could unspecify
110     // glGetStringi(GL_SHADING_LANGUAGE_VERSION, k), too.
111     // Since current context >= 4.5, use GLSL 4.50 core.
112     return SH_GLSL_450_CORE_OUTPUT;
113   } else if (context_version == 440) {
114     return SH_GLSL_440_CORE_OUTPUT;
115   } else if (context_version == 430) {
116     return SH_GLSL_430_CORE_OUTPUT;
117   } else if (context_version == 420) {
118     return SH_GLSL_420_CORE_OUTPUT;
119   } else if (context_version == 410) {
120     return SH_GLSL_410_CORE_OUTPUT;
121   } else if (context_version == 400) {
122     return SH_GLSL_400_CORE_OUTPUT;
123   } else if (context_version == 330) {
124     return SH_GLSL_330_CORE_OUTPUT;
125   } else if (context_version == 320) {
126     return SH_GLSL_150_CORE_OUTPUT;
127   }
128 
129   // Before OpenGL 3.2 we use the compatibility profile. Shading
130   // language version 130 restricted how sampler arrays can be indexed
131   // in loops, which causes problems like crbug.com/550487 .
132   //
133   // Also for any future specs that might be introduced between OpenGL
134   // 3.3 and OpenGL 4.0, at the time of writing, we use the
135   // compatibility profile.
136   return SH_GLSL_COMPATIBILITY_OUTPUT;
137 }
138 
139 ShaderTranslator::DestructionObserver::DestructionObserver() = default;
140 
141 ShaderTranslator::DestructionObserver::~DestructionObserver() = default;
142 
ShaderTranslator()143 ShaderTranslator::ShaderTranslator()
144     : compiler_(nullptr), compile_options_(0) {}
145 
Init(GLenum shader_type,ShShaderSpec shader_spec,const ShBuiltInResources * resources,ShShaderOutput shader_output_language,ShCompileOptions driver_bug_workarounds,bool gl_shader_interm_output)146 bool ShaderTranslator::Init(GLenum shader_type,
147                             ShShaderSpec shader_spec,
148                             const ShBuiltInResources* resources,
149                             ShShaderOutput shader_output_language,
150                             ShCompileOptions driver_bug_workarounds,
151                             bool gl_shader_interm_output) {
152   // Make sure Init is called only once.
153   DCHECK(compiler_ == nullptr);
154   DCHECK(shader_type == GL_FRAGMENT_SHADER || shader_type == GL_VERTEX_SHADER);
155   DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC ||
156          shader_spec == SH_GLES3_SPEC || shader_spec == SH_WEBGL2_SPEC);
157   DCHECK(resources != nullptr);
158 
159   g_translator_initializer.Get();
160 
161 
162   {
163     TRACE_EVENT0("gpu", "ShConstructCompiler");
164     compiler_ = sh::ConstructCompiler(shader_type, shader_spec,
165                                       shader_output_language, resources);
166   }
167 
168   compile_options_ =
169       SH_OBJECT_CODE | SH_VARIABLES | SH_ENFORCE_PACKING_RESTRICTIONS |
170       SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH |
171       SH_CLAMP_INDIRECT_ARRAY_BOUNDS | SH_EMULATE_GL_DRAW_ID |
172       SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE;
173   if (gl_shader_interm_output)
174     compile_options_ |= SH_INTERMEDIATE_TREE;
175   compile_options_ |= driver_bug_workarounds;
176   switch (shader_spec) {
177     case SH_WEBGL_SPEC:
178     case SH_WEBGL2_SPEC:
179       compile_options_ |= SH_INIT_OUTPUT_VARIABLES;
180       break;
181     default:
182       break;
183   }
184 
185   if (compiler_) {
186     options_affecting_compilation_ =
187         base::MakeRefCounted<OptionsAffectingCompilationString>(
188             std::string(":CompileOptions:" +
189                         base::NumberToString(GetCompileOptions())) +
190             sh::GetBuiltInResourcesString(compiler_));
191   }
192 
193   return compiler_ != nullptr;
194 }
195 
GetCompileOptions() const196 ShCompileOptions ShaderTranslator::GetCompileOptions() const {
197   return compile_options_;
198 }
199 
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) const200 bool ShaderTranslator::Translate(
201     const std::string& shader_source,
202     std::string* info_log,
203     std::string* translated_source,
204     int* shader_version,
205     AttributeMap* attrib_map,
206     UniformMap* uniform_map,
207     VaryingMap* varying_map,
208     InterfaceBlockMap* interface_block_map,
209     OutputVariableList* output_variable_list) const {
210   // Make sure this instance is initialized.
211   DCHECK(compiler_ != nullptr);
212 
213   bool success = false;
214   {
215     TRACE_EVENT0("gpu", "ShCompile");
216     const char* const shader_strings[] = { shader_source.c_str() };
217     success = sh::Compile(compiler_, shader_strings, 1, GetCompileOptions());
218   }
219   if (success) {
220     // Get translated shader.
221     if (translated_source) {
222       *translated_source = sh::GetObjectCode(compiler_);
223     }
224     // Get shader version.
225     *shader_version = sh::GetShaderVersion(compiler_);
226     // Get info for attribs, uniforms, varyings and output variables.
227     GetAttributes(compiler_, attrib_map);
228     GetUniforms(compiler_, uniform_map);
229     GetVaryings(compiler_, varying_map);
230     GetInterfaceBlocks(compiler_, interface_block_map);
231     GetOutputVariables(compiler_, output_variable_list);
232   }
233 
234   // Get info log.
235   if (info_log) {
236     *info_log = sh::GetInfoLog(compiler_);
237   }
238 
239   // We don't need results in the compiler anymore.
240   sh::ClearResults(compiler_);
241 
242   return success;
243 }
244 
245 OptionsAffectingCompilationString*
GetStringForOptionsThatWouldAffectCompilation() const246 ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation() const {
247   return options_affecting_compilation_.get();
248 }
249 
AddDestructionObserver(DestructionObserver * observer)250 void ShaderTranslator::AddDestructionObserver(
251     DestructionObserver* observer) {
252   destruction_observers_.AddObserver(observer);
253 }
254 
RemoveDestructionObserver(DestructionObserver * observer)255 void ShaderTranslator::RemoveDestructionObserver(
256     DestructionObserver* observer) {
257   destruction_observers_.RemoveObserver(observer);
258 }
259 
~ShaderTranslator()260 ShaderTranslator::~ShaderTranslator() {
261   for (auto& observer : destruction_observers_)
262     observer.OnDestruct(this);
263 
264   if (compiler_ != nullptr)
265     sh::Destruct(compiler_);
266 }
267 
268 }  // namespace gles2
269 }  // namespace gpu
270 
271