/src/mozilla-central/dom/canvas/WebGLShaderValidator.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "WebGLShaderValidator.h" |
7 | | |
8 | | #include "gfxPrefs.h" |
9 | | #include "GLContext.h" |
10 | | #include "mozilla/gfx/Logging.h" |
11 | | #include "mozilla/Preferences.h" |
12 | | #include "MurmurHash3.h" |
13 | | #include "nsPrintfCString.h" |
14 | | #include <string> |
15 | | #include <vector> |
16 | | #include "WebGLContext.h" |
17 | | |
18 | | namespace mozilla { |
19 | | namespace webgl { |
20 | | |
21 | | uint64_t |
22 | | IdentifierHashFunc(const char* name, size_t len) |
23 | 0 | { |
24 | 0 | // NB: we use the x86 function everywhere, even though it's suboptimal perf |
25 | 0 | // on x64. They return different results; not sure if that's a requirement. |
26 | 0 | uint64_t hash[2]; |
27 | 0 | MurmurHash3_x86_128(name, len, 0, hash); |
28 | 0 | return hash[0]; |
29 | 0 | } |
30 | | |
31 | | static ShCompileOptions |
32 | | ChooseValidatorCompileOptions(const ShBuiltInResources& resources, |
33 | | const mozilla::gl::GLContext* gl) |
34 | 0 | { |
35 | 0 | ShCompileOptions options = SH_VARIABLES | |
36 | 0 | SH_ENFORCE_PACKING_RESTRICTIONS | |
37 | 0 | SH_OBJECT_CODE | |
38 | 0 | SH_INIT_GL_POSITION | |
39 | 0 | SH_INITIALIZE_UNINITIALIZED_LOCALS | |
40 | 0 | SH_INIT_OUTPUT_VARIABLES; |
41 | 0 |
|
42 | 0 | #ifndef XP_MACOSX |
43 | 0 | // We want to do this everywhere, but to do this on Mac, we need |
44 | 0 | // to do it only on Mac OSX > 10.6 as this causes the shader |
45 | 0 | // compiler in 10.6 to crash |
46 | 0 | options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS; |
47 | 0 | #endif |
48 | 0 |
|
49 | 0 | if (gl->WorkAroundDriverBugs()) { |
50 | | #ifdef XP_MACOSX |
51 | | // Work around https://bugs.webkit.org/show_bug.cgi?id=124684, |
52 | | // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb |
53 | | options |= SH_UNFOLD_SHORT_CIRCUIT; |
54 | | |
55 | | // Work around that Mac drivers handle struct scopes incorrectly. |
56 | | options |= SH_REGENERATE_STRUCT_NAMES; |
57 | | options |= SH_INIT_OUTPUT_VARIABLES; |
58 | | |
59 | | // Work around that Intel drivers on Mac OSX handle for-loop incorrectly. |
60 | | if (gl->Vendor() == gl::GLVendor::Intel) { |
61 | | options |= SH_ADD_AND_TRUE_TO_LOOP_CONDITION; |
62 | | } |
63 | | #endif |
64 | |
|
65 | 0 | if (!gl->IsANGLE() && gl->Vendor() == gl::GLVendor::Intel) { |
66 | 0 | // Failures on at least Windows+Intel+OGL on: |
67 | 0 | // conformance/glsl/constructors/glsl-construct-mat2.html |
68 | 0 | options |= SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS; |
69 | 0 | } |
70 | 0 | } |
71 | 0 |
|
72 | 0 | if (gfxPrefs::WebGLAllANGLEOptions()) { |
73 | 0 | options = -1; |
74 | 0 |
|
75 | 0 | options ^= SH_INTERMEDIATE_TREE; |
76 | 0 | options ^= SH_LINE_DIRECTIVES; |
77 | 0 | options ^= SH_SOURCE_PATH; |
78 | 0 |
|
79 | 0 | options ^= SH_LIMIT_EXPRESSION_COMPLEXITY; |
80 | 0 | options ^= SH_LIMIT_CALL_STACK_DEPTH; |
81 | 0 |
|
82 | 0 | options ^= SH_EXPAND_SELECT_HLSL_INTEGER_POW_EXPRESSIONS; |
83 | 0 | options ^= SH_HLSL_GET_DIMENSIONS_IGNORES_BASE_LEVEL; |
84 | 0 |
|
85 | 0 | options ^= SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT; |
86 | 0 | options ^= SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3; |
87 | 0 | } |
88 | 0 |
|
89 | 0 | if (resources.MaxExpressionComplexity > 0) { |
90 | 0 | options |= SH_LIMIT_EXPRESSION_COMPLEXITY; |
91 | 0 | } |
92 | 0 | if (resources.MaxCallStackDepth > 0) { |
93 | 0 | options |= SH_LIMIT_CALL_STACK_DEPTH; |
94 | 0 | } |
95 | 0 |
|
96 | 0 | return options; |
97 | 0 | } |
98 | | |
99 | | } // namespace webgl |
100 | | |
101 | | //////////////////////////////////////// |
102 | | |
103 | | static ShShaderOutput |
104 | | ShaderOutput(gl::GLContext* gl) |
105 | 0 | { |
106 | 0 | if (gl->IsGLES()) { |
107 | 0 | return SH_ESSL_OUTPUT; |
108 | 0 | } else { |
109 | 0 | uint32_t version = gl->ShadingLanguageVersion(); |
110 | 0 | switch (version) { |
111 | 0 | case 100: return SH_GLSL_COMPATIBILITY_OUTPUT; |
112 | 0 | case 120: return SH_GLSL_COMPATIBILITY_OUTPUT; |
113 | 0 | case 130: return SH_GLSL_130_OUTPUT; |
114 | 0 | case 140: return SH_GLSL_140_OUTPUT; |
115 | 0 | case 150: return SH_GLSL_150_CORE_OUTPUT; |
116 | 0 | case 330: return SH_GLSL_330_CORE_OUTPUT; |
117 | 0 | case 400: return SH_GLSL_400_CORE_OUTPUT; |
118 | 0 | case 410: return SH_GLSL_410_CORE_OUTPUT; |
119 | 0 | case 420: return SH_GLSL_420_CORE_OUTPUT; |
120 | 0 | case 430: return SH_GLSL_430_CORE_OUTPUT; |
121 | 0 | case 440: return SH_GLSL_440_CORE_OUTPUT; |
122 | 0 | default: |
123 | 0 | if (version >= 450) { |
124 | 0 | // "OpenGL 4.6 is also guaranteed to support all previous versions of the |
125 | 0 | // OpenGL Shading Language back to version 1.10." |
126 | 0 | return SH_GLSL_450_CORE_OUTPUT; |
127 | 0 | } |
128 | 0 | gfxCriticalNote << "Unexpected GLSL version: " << version; |
129 | 0 | } |
130 | 0 | } |
131 | 0 |
|
132 | 0 | return SH_GLSL_COMPATIBILITY_OUTPUT; |
133 | 0 | } |
134 | | |
135 | | webgl::ShaderValidator* |
136 | | WebGLContext::CreateShaderValidator(GLenum shaderType) const |
137 | 0 | { |
138 | 0 | if (mBypassShaderValidation) |
139 | 0 | return nullptr; |
140 | 0 | |
141 | 0 | const auto spec = (IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC); |
142 | 0 | const auto outputLanguage = ShaderOutput(gl); |
143 | 0 |
|
144 | 0 | ShBuiltInResources resources; |
145 | 0 | memset(&resources, 0, sizeof(resources)); |
146 | 0 | sh::InitBuiltInResources(&resources); |
147 | 0 |
|
148 | 0 | resources.HashFunction = webgl::IdentifierHashFunc; |
149 | 0 |
|
150 | 0 | resources.MaxVertexAttribs = mGLMaxVertexAttribs; |
151 | 0 | resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors; |
152 | 0 | resources.MaxVaryingVectors = mGLMaxVaryingVectors; |
153 | 0 | resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits; |
154 | 0 | resources.MaxCombinedTextureImageUnits = mGLMaxCombinedTextureImageUnits; |
155 | 0 | resources.MaxTextureImageUnits = mGLMaxFragmentTextureImageUnits; |
156 | 0 | resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors; |
157 | 0 |
|
158 | 0 | const bool hasMRTs = (IsWebGL2() || |
159 | 0 | IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)); |
160 | 0 | resources.MaxDrawBuffers = (hasMRTs ? mGLMaxDrawBuffers : 1); |
161 | 0 |
|
162 | 0 | if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth)) |
163 | 0 | resources.EXT_frag_depth = 1; |
164 | 0 |
|
165 | 0 | if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) |
166 | 0 | resources.OES_standard_derivatives = 1; |
167 | 0 |
|
168 | 0 | if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) |
169 | 0 | resources.EXT_draw_buffers = 1; |
170 | 0 |
|
171 | 0 | if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod)) |
172 | 0 | resources.EXT_shader_texture_lod = 1; |
173 | 0 |
|
174 | 0 | // Tell ANGLE to allow highp in frag shaders. (unless disabled) |
175 | 0 | // If underlying GLES doesn't have highp in frag shaders, it should complain anyways. |
176 | 0 | resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1; |
177 | 0 |
|
178 | 0 | if (gl->WorkAroundDriverBugs()) { |
179 | | #ifdef XP_MACOSX |
180 | | if (gl->Vendor() == gl::GLVendor::NVIDIA) { |
181 | | // Work around bug 890432 |
182 | | resources.MaxExpressionComplexity = 1000; |
183 | | } |
184 | | #endif |
185 | | } |
186 | 0 |
|
187 | 0 | const auto compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl); |
188 | 0 | return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources, |
189 | 0 | compileOptions); |
190 | 0 | } |
191 | | |
192 | | //////////////////////////////////////// |
193 | | |
194 | | namespace webgl { |
195 | | |
196 | | /*static*/ ShaderValidator* |
197 | | ShaderValidator::Create(GLenum shaderType, ShShaderSpec spec, |
198 | | ShShaderOutput outputLanguage, |
199 | | const ShBuiltInResources& resources, |
200 | | ShCompileOptions compileOptions) |
201 | 0 | { |
202 | 0 | ShHandle handle = sh::ConstructCompiler(shaderType, spec, outputLanguage, &resources); |
203 | 0 | if (!handle) |
204 | 0 | return nullptr; |
205 | 0 | |
206 | 0 | return new ShaderValidator(handle, compileOptions, resources.MaxVaryingVectors); |
207 | 0 | } |
208 | | |
209 | | ShaderValidator::~ShaderValidator() |
210 | 0 | { |
211 | 0 | sh::Destruct(mHandle); |
212 | 0 | } |
213 | | |
214 | | bool |
215 | | ShaderValidator::ValidateAndTranslate(const char* source) |
216 | 0 | { |
217 | 0 | MOZ_ASSERT(!mHasRun); |
218 | 0 | mHasRun = true; |
219 | 0 |
|
220 | 0 | const char* const parts[] = { |
221 | 0 | source |
222 | 0 | }; |
223 | 0 | return sh::Compile(mHandle, parts, ArrayLength(parts), mCompileOptions); |
224 | 0 | } |
225 | | |
226 | | void |
227 | | ShaderValidator::GetInfoLog(nsACString* out) const |
228 | 0 | { |
229 | 0 | MOZ_ASSERT(mHasRun); |
230 | 0 |
|
231 | 0 | const std::string &log = sh::GetInfoLog(mHandle); |
232 | 0 | out->Assign(log.data(), log.length()); |
233 | 0 | } |
234 | | |
235 | | void |
236 | | ShaderValidator::GetOutput(nsACString* out) const |
237 | 0 | { |
238 | 0 | MOZ_ASSERT(mHasRun); |
239 | 0 |
|
240 | 0 | const std::string &output = sh::GetObjectCode(mHandle); |
241 | 0 | out->Assign(output.data(), output.length()); |
242 | 0 | } |
243 | | |
244 | | template<size_t N> |
245 | | static bool |
246 | | StartsWith(const std::string& haystack, const char (&needle)[N]) |
247 | 0 | { |
248 | 0 | return haystack.compare(0, N - 1, needle) == 0; |
249 | 0 | } |
250 | | |
251 | | bool |
252 | | ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const |
253 | 0 | { |
254 | 0 | if (!prev) { |
255 | 0 | nsPrintfCString error("Passed in NULL prev ShaderValidator."); |
256 | 0 | *out_log = error; |
257 | 0 | return false; |
258 | 0 | } |
259 | 0 | |
260 | 0 | const auto shaderVersion = sh::GetShaderVersion(mHandle); |
261 | 0 | if (sh::GetShaderVersion(prev->mHandle) != shaderVersion) { |
262 | 0 | nsPrintfCString error("Vertex shader version %d does not match" |
263 | 0 | " fragment shader version %d.", |
264 | 0 | sh::GetShaderVersion(prev->mHandle), |
265 | 0 | sh::GetShaderVersion(mHandle)); |
266 | 0 | *out_log = error; |
267 | 0 | return false; |
268 | 0 | } |
269 | 0 | |
270 | 0 | { |
271 | 0 | const std::vector<sh::Uniform>* vertPtr = sh::GetUniforms(prev->mHandle); |
272 | 0 | const std::vector<sh::Uniform>* fragPtr = sh::GetUniforms(mHandle); |
273 | 0 | if (!vertPtr || !fragPtr) { |
274 | 0 | nsPrintfCString error("Could not create uniform list."); |
275 | 0 | *out_log = error; |
276 | 0 | return false; |
277 | 0 | } |
278 | 0 | |
279 | 0 | for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) { |
280 | 0 | for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) { |
281 | 0 | if (itrVert->name != itrFrag->name) |
282 | 0 | continue; |
283 | 0 | |
284 | 0 | if (!itrVert->isSameUniformAtLinkTime(*itrFrag)) { |
285 | 0 | nsPrintfCString error("Uniform `%s` is not linkable between" |
286 | 0 | " attached shaders.", |
287 | 0 | itrFrag->name.c_str()); |
288 | 0 | *out_log = error; |
289 | 0 | return false; |
290 | 0 | } |
291 | 0 | |
292 | 0 | break; |
293 | 0 | } |
294 | 0 | } |
295 | 0 | } |
296 | 0 | { |
297 | 0 | const auto vertVars = sh::GetInterfaceBlocks(prev->mHandle); |
298 | 0 | const auto fragVars = sh::GetInterfaceBlocks(mHandle); |
299 | 0 | if (!vertVars || !fragVars) { |
300 | 0 | nsPrintfCString error("Could not create uniform block list."); |
301 | 0 | *out_log = error; |
302 | 0 | return false; |
303 | 0 | } |
304 | 0 | |
305 | 0 | for (const auto& fragVar : *fragVars) { |
306 | 0 | for (const auto& vertVar : *vertVars) { |
307 | 0 | if (vertVar.name != fragVar.name) |
308 | 0 | continue; |
309 | 0 | |
310 | 0 | if (!vertVar.isSameInterfaceBlockAtLinkTime(fragVar)) { |
311 | 0 | nsPrintfCString error("Interface block `%s` is not linkable between" |
312 | 0 | " attached shaders.", |
313 | 0 | fragVar.name.c_str()); |
314 | 0 | *out_log = error; |
315 | 0 | return false; |
316 | 0 | } |
317 | 0 | |
318 | 0 | break; |
319 | 0 | } |
320 | 0 | } |
321 | 0 | } |
322 | 0 |
|
323 | 0 | const auto& vertVaryings = sh::GetVaryings(prev->mHandle); |
324 | 0 | const auto& fragVaryings = sh::GetVaryings(mHandle); |
325 | 0 | if (!vertVaryings || !fragVaryings) { |
326 | 0 | nsPrintfCString error("Could not create varying list."); |
327 | 0 | *out_log = error; |
328 | 0 | return false; |
329 | 0 | } |
330 | 0 | |
331 | 0 | { |
332 | 0 | std::vector<sh::ShaderVariable> staticUseVaryingList; |
333 | 0 |
|
334 | 0 | for (const auto& fragVarying : *fragVaryings) { |
335 | 0 | static const char prefix[] = "gl_"; |
336 | 0 | if (StartsWith(fragVarying.name, prefix)) { |
337 | 0 | if (fragVarying.staticUse) { |
338 | 0 | staticUseVaryingList.push_back(fragVarying); |
339 | 0 | } |
340 | 0 | continue; |
341 | 0 | } |
342 | 0 |
|
343 | 0 | bool definedInVertShader = false; |
344 | 0 | bool staticVertUse = false; |
345 | 0 |
|
346 | 0 | for (const auto& vertVarying : *vertVaryings) { |
347 | 0 | if (vertVarying.name != fragVarying.name) |
348 | 0 | continue; |
349 | 0 | |
350 | 0 | if (!vertVarying.isSameVaryingAtLinkTime(fragVarying, shaderVersion)) { |
351 | 0 | nsPrintfCString error("Varying `%s`is not linkable between" |
352 | 0 | " attached shaders.", |
353 | 0 | fragVarying.name.c_str()); |
354 | 0 | *out_log = error; |
355 | 0 | return false; |
356 | 0 | } |
357 | 0 | |
358 | 0 | definedInVertShader = true; |
359 | 0 | staticVertUse = vertVarying.staticUse; |
360 | 0 | break; |
361 | 0 | } |
362 | 0 |
|
363 | 0 | if (!definedInVertShader && fragVarying.staticUse) { |
364 | 0 | nsPrintfCString error("Varying `%s` has static-use in the frag" |
365 | 0 | " shader, but is undeclared in the vert" |
366 | 0 | " shader.", fragVarying.name.c_str()); |
367 | 0 | *out_log = error; |
368 | 0 | return false; |
369 | 0 | } |
370 | 0 | |
371 | 0 | if (staticVertUse && fragVarying.staticUse) { |
372 | 0 | staticUseVaryingList.push_back(fragVarying); |
373 | 0 | } |
374 | 0 | } |
375 | 0 |
|
376 | 0 | if (!sh::CheckVariablesWithinPackingLimits(mMaxVaryingVectors, |
377 | 0 | staticUseVaryingList)) |
378 | 0 | { |
379 | 0 | *out_log = "Statically used varyings do not fit within packing limits. (see" |
380 | 0 | " GLSL ES Specification 1.0.17, p111)"; |
381 | 0 | return false; |
382 | 0 | } |
383 | 0 | } |
384 | 0 | |
385 | 0 | if (shaderVersion == 100) { |
386 | 0 | // Enforce ESSL1 invariant linking rules. |
387 | 0 | bool isInvariant_Position = false; |
388 | 0 | bool isInvariant_PointSize = false; |
389 | 0 | bool isInvariant_FragCoord = false; |
390 | 0 | bool isInvariant_PointCoord = false; |
391 | 0 |
|
392 | 0 | for (const auto& varying : *vertVaryings) { |
393 | 0 | if (varying.name == "gl_Position") { |
394 | 0 | isInvariant_Position = varying.isInvariant; |
395 | 0 | } else if (varying.name == "gl_PointSize") { |
396 | 0 | isInvariant_PointSize = varying.isInvariant; |
397 | 0 | } |
398 | 0 | } |
399 | 0 |
|
400 | 0 | for (const auto& varying : *fragVaryings) { |
401 | 0 | if (varying.name == "gl_FragCoord") { |
402 | 0 | isInvariant_FragCoord = varying.isInvariant; |
403 | 0 | } else if (varying.name == "gl_PointCoord") { |
404 | 0 | isInvariant_PointCoord = varying.isInvariant; |
405 | 0 | } |
406 | 0 | } |
407 | 0 |
|
408 | 0 | //// |
409 | 0 |
|
410 | 0 | const auto fnCanBuiltInsLink = [](bool vertIsInvariant, bool fragIsInvariant) { |
411 | 0 | if (vertIsInvariant) |
412 | 0 | return true; |
413 | 0 | |
414 | 0 | return !fragIsInvariant; |
415 | 0 | }; |
416 | 0 |
|
417 | 0 | if (!fnCanBuiltInsLink(isInvariant_Position, isInvariant_FragCoord)) { |
418 | 0 | *out_log = "gl_Position must be invariant if gl_FragCoord is. (see GLSL ES" |
419 | 0 | " Specification 1.0.17, p39)"; |
420 | 0 | return false; |
421 | 0 | } |
422 | 0 | |
423 | 0 | if (!fnCanBuiltInsLink(isInvariant_PointSize, isInvariant_PointCoord)) { |
424 | 0 | *out_log = "gl_PointSize must be invariant if gl_PointCoord is. (see GLSL ES" |
425 | 0 | " Specification 1.0.17, p39)"; |
426 | 0 | return false; |
427 | 0 | } |
428 | 0 | } |
429 | 0 | |
430 | 0 | return true; |
431 | 0 | } |
432 | | |
433 | | size_t |
434 | | ShaderValidator::CalcNumSamplerUniforms() const |
435 | 0 | { |
436 | 0 | size_t accum = 0; |
437 | 0 |
|
438 | 0 | const std::vector<sh::Uniform>& uniforms = *sh::GetUniforms(mHandle); |
439 | 0 |
|
440 | 0 | for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) { |
441 | 0 | GLenum type = itr->type; |
442 | 0 | if (type == LOCAL_GL_SAMPLER_2D || |
443 | 0 | type == LOCAL_GL_SAMPLER_CUBE) |
444 | 0 | { |
445 | 0 | accum += itr->getArraySizeProduct(); |
446 | 0 | } |
447 | 0 | } |
448 | 0 |
|
449 | 0 | return accum; |
450 | 0 | } |
451 | | |
452 | | size_t |
453 | | ShaderValidator::NumAttributes() const |
454 | 0 | { |
455 | 0 | return sh::GetAttributes(mHandle)->size(); |
456 | 0 | } |
457 | | |
458 | | // Attribs cannot be structs or arrays, and neither can vertex inputs in ES3. |
459 | | // Therefore, attrib names are always simple. |
460 | | bool |
461 | | ShaderValidator::FindAttribUserNameByMappedName(const std::string& mappedName, |
462 | | const std::string** const out_userName) const |
463 | 0 | { |
464 | 0 | const std::vector<sh::Attribute>& attribs = *sh::GetAttributes(mHandle); |
465 | 0 | for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) { |
466 | 0 | if (itr->mappedName == mappedName) { |
467 | 0 | *out_userName = &(itr->name); |
468 | 0 | return true; |
469 | 0 | } |
470 | 0 | } |
471 | 0 |
|
472 | 0 | return false; |
473 | 0 | } |
474 | | |
475 | | bool |
476 | | ShaderValidator::FindAttribMappedNameByUserName(const std::string& userName, |
477 | | const std::string** const out_mappedName) const |
478 | 0 | { |
479 | 0 | const std::vector<sh::Attribute>& attribs = *sh::GetAttributes(mHandle); |
480 | 0 | for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) { |
481 | 0 | if (itr->name == userName) { |
482 | 0 | *out_mappedName = &(itr->mappedName); |
483 | 0 | return true; |
484 | 0 | } |
485 | 0 | } |
486 | 0 |
|
487 | 0 | return false; |
488 | 0 | } |
489 | | |
490 | | bool |
491 | | ShaderValidator::FindVaryingByMappedName(const std::string& mappedName, |
492 | | std::string* const out_userName, |
493 | | bool* const out_isArray) const |
494 | 0 | { |
495 | 0 | const std::vector<sh::Varying>& varyings = *sh::GetVaryings(mHandle); |
496 | 0 | for (auto itr = varyings.begin(); itr != varyings.end(); ++itr) { |
497 | 0 | const sh::ShaderVariable* found; |
498 | 0 | if (!itr->findInfoByMappedName(mappedName, &found, out_userName)) |
499 | 0 | continue; |
500 | 0 | |
501 | 0 | *out_isArray = found->isArray(); |
502 | 0 | return true; |
503 | 0 | } |
504 | 0 |
|
505 | 0 | return false; |
506 | 0 | } |
507 | | |
508 | | bool |
509 | | ShaderValidator::FindVaryingMappedNameByUserName(const std::string& userName, |
510 | | const std::string** const out_mappedName) const |
511 | 0 | { |
512 | 0 | const std::vector<sh::Varying>& attribs = *sh::GetVaryings(mHandle); |
513 | 0 | for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) { |
514 | 0 | if (itr->name == userName) { |
515 | 0 | *out_mappedName = &(itr->mappedName); |
516 | 0 | return true; |
517 | 0 | } |
518 | 0 | } |
519 | 0 |
|
520 | 0 | return false; |
521 | 0 | } |
522 | | // This must handle names like "foo.bar[0]". |
523 | | bool |
524 | | ShaderValidator::FindUniformByMappedName(const std::string& mappedName, |
525 | | std::string* const out_userName, |
526 | | bool* const out_isArray) const |
527 | 0 | { |
528 | 0 | const std::vector<sh::Uniform>& uniforms = *sh::GetUniforms(mHandle); |
529 | 0 | for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) { |
530 | 0 | const sh::ShaderVariable* found; |
531 | 0 | if (!itr->findInfoByMappedName(mappedName, &found, out_userName)) |
532 | 0 | continue; |
533 | 0 | |
534 | 0 | *out_isArray = found->isArray(); |
535 | 0 | return true; |
536 | 0 | } |
537 | 0 |
|
538 | 0 | const size_t dotPos = mappedName.find("."); |
539 | 0 |
|
540 | 0 | const std::vector<sh::InterfaceBlock>& interfaces = *sh::GetInterfaceBlocks(mHandle); |
541 | 0 | for (const auto& interface : interfaces) { |
542 | 0 |
|
543 | 0 | std::string mappedFieldName; |
544 | 0 | const bool hasInstanceName = !interface.instanceName.empty(); |
545 | 0 |
|
546 | 0 | // If the InterfaceBlock has an instanceName, all variables defined |
547 | 0 | // within the block are qualified with the block name, as opposed |
548 | 0 | // to being placed in the global scope. |
549 | 0 | if (hasInstanceName) { |
550 | 0 |
|
551 | 0 | // If mappedName has no block name prefix, skip |
552 | 0 | if (std::string::npos == dotPos) |
553 | 0 | continue; |
554 | 0 | |
555 | 0 | // If mappedName has a block name prefix that doesn't match, skip |
556 | 0 | const std::string mappedInterfaceBlockName = mappedName.substr(0, dotPos); |
557 | 0 | if (interface.mappedName != mappedInterfaceBlockName) |
558 | 0 | continue; |
559 | 0 | |
560 | 0 | mappedFieldName = mappedName.substr(dotPos + 1); |
561 | 0 | } else { |
562 | 0 | mappedFieldName = mappedName; |
563 | 0 | } |
564 | 0 |
|
565 | 0 | for (const auto& field : interface.fields) { |
566 | 0 | const sh::ShaderVariable* found; |
567 | 0 |
|
568 | 0 | if (!field.findInfoByMappedName(mappedFieldName, &found, out_userName)) |
569 | 0 | continue; |
570 | 0 | |
571 | 0 | if (hasInstanceName) { |
572 | 0 | // Prepend the user name of the interface that matched |
573 | 0 | *out_userName = interface.name + "." + *out_userName; |
574 | 0 | } |
575 | 0 |
|
576 | 0 | *out_isArray = found->isArray(); |
577 | 0 | return true; |
578 | 0 | } |
579 | 0 | } |
580 | 0 |
|
581 | 0 | return false; |
582 | 0 | } |
583 | | |
584 | | bool |
585 | | ShaderValidator::UnmapUniformBlockName(const nsACString& baseMappedName, |
586 | | nsCString* const out_baseUserName) const |
587 | 0 | { |
588 | 0 | const std::vector<sh::InterfaceBlock>& interfaces = *sh::GetInterfaceBlocks(mHandle); |
589 | 0 | for (const auto& interface : interfaces) { |
590 | 0 | const nsDependentCString interfaceMappedName(interface.mappedName.data(), |
591 | 0 | interface.mappedName.size()); |
592 | 0 | if (baseMappedName == interfaceMappedName) { |
593 | 0 | *out_baseUserName = interface.name.data(); |
594 | 0 | return true; |
595 | 0 | } |
596 | 0 | } |
597 | 0 |
|
598 | 0 | return false; |
599 | 0 | } |
600 | | |
601 | | void |
602 | | ShaderValidator::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const |
603 | 0 | { |
604 | 0 | const auto* fragOutputs = sh::GetOutputVariables(mHandle); |
605 | 0 |
|
606 | 0 | if (fragOutputs) { |
607 | 0 | for (const auto& fragOutput : *fragOutputs) { |
608 | 0 | out_FragOutputs.insert({nsCString(fragOutput.name.c_str()), |
609 | 0 | nsCString(fragOutput.mappedName.c_str())}); |
610 | 0 | } |
611 | 0 | } |
612 | 0 | } |
613 | | |
614 | | } // namespace webgl |
615 | | } // namespace mozilla |