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