Coverage Report

Created: 2018-09-25 14:53

/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