Coverage Report

Created: 2026-10-17 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glslang/glslang/MachineIndependent/reflection.cpp
Line
Count
Source
1
//
2
// Copyright (C) 2013-2016 LunarG, Inc.
3
//
4
// All rights reserved.
5
//
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions
8
// are met:
9
//
10
//    Redistributions of source code must retain the above copyright
11
//    notice, this list of conditions and the following disclaimer.
12
//
13
//    Redistributions in binary form must reproduce the above
14
//    copyright notice, this list of conditions and the following
15
//    disclaimer in the documentation and/or other materials provided
16
//    with the distribution.
17
//
18
//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
19
//    contributors may be used to endorse or promote products derived
20
//    from this software without specific prior written permission.
21
//
22
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
// POSSIBILITY OF SUCH DAMAGE.
34
//
35
36
#include "../Include/Common.h"
37
#include "reflection.h"
38
#include "LiveTraverser.h"
39
#include "localintermediate.h"
40
41
#include "gl_types.h"
42
43
//
44
// Grow the reflection database through a friend traverser class of TReflection and a
45
// collection of functions to do a liveness traversal that note what uniforms are used
46
// in semantically non-dead code.
47
//
48
// Can be used multiple times, once per stage, to grow a program reflection.
49
//
50
// High-level algorithm for one stage:
51
//
52
// 1. Put the entry point on the list of live functions.
53
//
54
// 2. Traverse any live function, while skipping if-tests with a compile-time constant
55
//    condition of false, and while adding any encountered function calls to the live
56
//    function list.
57
//
58
//    Repeat until the live function list is empty.
59
//
60
// 3. Add any encountered uniform variables and blocks to the reflection database.
61
//
62
// Can be attempted with a failed link, but will return false if recursion had been detected, or
63
// there wasn't exactly one entry point.
64
//
65
66
namespace glslang {
67
68
//
69
// The traverser: mostly pass through, except
70
//  - processing binary nodes to see if they are dereferences of an aggregates to track
71
//  - processing symbol nodes to see if they are non-aggregate objects to track
72
//
73
// This ignores semantically dead code by using TLiveTraverser.
74
//
75
// This is in the glslang namespace directly so it can be a friend of TReflection.
76
//
77
78
class TReflectionTraverser : public TIntermTraverser {
79
public:
80
    TReflectionTraverser(const TIntermediate& i, TReflection& r) :
81
0
                       TIntermTraverser(), intermediate(i), reflection(r), updateStageMasks(true) { }
82
83
    virtual bool visitBinary(TVisit, TIntermBinary* node);
84
    virtual void visitSymbol(TIntermSymbol* base);
85
86
    // Add a simple reference to a uniform variable to the uniform database, no dereference involved.
87
    // However, no dereference doesn't mean simple... it could be a complex aggregate.
88
    void addUniform(const TIntermSymbol& base)
89
0
    {
90
0
        if (processedDerefs.find(&base) == processedDerefs.end()) {
91
0
            processedDerefs.insert(&base);
92
93
0
            int blockIndex = -1;
94
0
            int offset     = -1;
95
0
            TList<TIntermBinary*> derefs;
96
0
            TString baseName = base.getName();
97
98
0
            if (base.getType().getBasicType() == EbtBlock) {
99
0
                offset = 0;
100
0
                bool anonymous = IsAnonymous(baseName);
101
0
                const TString& blockName = base.getType().getTypeName();
102
103
0
                if (!anonymous)
104
0
                    baseName = blockName;
105
0
                else
106
0
                    baseName = "";
107
108
0
                blockIndex = addBlockName(blockName, base.getType(), intermediate.getBlockSize(base.getType()));
109
0
            }
110
111
            // Use a degenerate (empty) set of dereferences to immediately put as at the end of
112
            // the dereference change expected by blowUpActiveAggregate.
113
0
            blowUpActiveAggregate(base.getType(), baseName, derefs, derefs.end(), offset, blockIndex, 0, -1, 0,
114
0
                                    base.getQualifier().storage, updateStageMasks);
115
0
        }
116
0
    }
117
118
    void addPipeIOVariable(const TIntermSymbol& base)
119
0
    {
120
0
        if (processedDerefs.find(&base) == processedDerefs.end()) {
121
0
            processedDerefs.insert(&base);
122
123
0
            const TString &name = base.getName();
124
0
            const TType &type = base.getType();
125
0
            const bool input = base.getQualifier().isPipeInput();
126
127
0
            TReflection::TMapIndexToReflection &ioItems =
128
0
                input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
129
130
131
0
            TReflection::TNameToIndex &ioMapper =
132
0
                input ? reflection.pipeInNameToIndex : reflection.pipeOutNameToIndex;
133
134
0
            if (reflection.options & EShReflectionUnwrapIOBlocks) {
135
0
                bool anonymous = IsAnonymous(name);
136
137
0
                TString baseName;
138
0
                if (type.getBasicType() == EbtBlock) {
139
0
                    baseName = anonymous ? TString() : type.getTypeName();
140
0
                } else {
141
0
                    baseName = anonymous ? TString() : name;
142
0
                }
143
144
                // by convention if this is an arrayed block we ignore the array in the reflection
145
0
                if (type.isArray() && type.getBasicType() == EbtBlock) {
146
0
                    blowUpIOAggregate(input, baseName, TType(type, 0));
147
0
                } else {
148
0
                    blowUpIOAggregate(input, baseName, type);
149
0
                }
150
0
            } else {
151
0
                TReflection::TNameToIndex::const_iterator it = ioMapper.find(name.c_str());
152
0
                if (it == ioMapper.end()) {
153
                    // seperate pipe i/o params from uniforms and blocks
154
                    // in is only for input in first stage as out is only for last stage. check traverse in call stack.
155
0
                    ioMapper[name.c_str()] = static_cast<int>(ioItems.size());
156
0
                    ioItems.push_back(
157
0
                        TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
158
0
                    EShLanguageMask& stages = ioItems.back().stages;
159
0
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
160
0
                } else {
161
0
                    EShLanguageMask& stages = ioItems[it->second].stages;
162
0
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
163
0
                }
164
0
            }
165
0
        }
166
0
    }
167
168
    // Lookup or calculate the offset of all block members at once, using the recursively
169
    // defined block offset rules.
170
    void getOffsets(const TType& type, TVector<int>& offsets)
171
0
    {
172
0
        const TTypeList& memberList = *type.getStruct();
173
0
        int memberSize = 0;
174
0
        int offset = 0;
175
176
0
        for (size_t m = 0; m < offsets.size(); ++m) {
177
            // if the user supplied an offset, snap to it now
178
0
            if (memberList[m].type->getQualifier().hasOffset())
179
0
                offset = memberList[m].type->getQualifier().layoutOffset;
180
181
            // calculate the offset of the next member and align the current offset to this member
182
0
            intermediate.updateOffset(type, *memberList[m].type, offset, memberSize);
183
184
            // save the offset of this member
185
0
            offsets[m] = offset;
186
187
            // update for the next member
188
0
            offset += memberSize;
189
0
        }
190
0
    }
191
192
    // Calculate the stride of an array type
193
    int getArrayStride(const TType& baseType, const TType& type)
194
0
    {
195
0
        int dummySize;
196
0
        int stride;
197
198
        // consider blocks to have 0 stride, so that all offsets are relative to the start of their block
199
0
        if (type.getBasicType() == EbtBlock)
200
0
            return 0;
201
202
0
        TLayoutMatrix subMatrixLayout = type.getQualifier().layoutMatrix;
203
0
        intermediate.getMemberAlignment(type, dummySize, stride,
204
0
                                        baseType.getQualifier().layoutPacking,
205
0
                                        subMatrixLayout != ElmNone
206
0
                                            ? subMatrixLayout == ElmRowMajor
207
0
                                            : baseType.getQualifier().layoutMatrix == ElmRowMajor);
208
209
0
        return stride;
210
0
    }
211
212
    // count the total number of leaf members from iterating out of a block type
213
    int countAggregateMembers(const TType& parentType)
214
0
    {
215
0
        if (! parentType.isStruct())
216
0
            return 1;
217
218
0
        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
219
220
0
        bool blockParent = (parentType.getBasicType() == EbtBlock && parentType.getQualifier().storage == EvqBuffer);
221
222
0
        const TTypeList &memberList = *parentType.getStruct();
223
224
0
        int ret = 0;
225
226
0
        for (size_t i = 0; i < memberList.size(); i++)
227
0
        {
228
0
            const TType &memberType = *memberList[i].type;
229
0
            int numMembers = countAggregateMembers(memberType);
230
            // for sized arrays of structs, apply logic to expand out the same as we would below in
231
            // blowUpActiveAggregate
232
0
            if (memberType.isArray() && ! memberType.getArraySizes()->hasUnsized() && memberType.isStruct()) {
233
0
                if (! strictArraySuffix || ! blockParent)
234
0
                    numMembers *= memberType.getArraySizes()->getCumulativeSize();
235
0
            }
236
0
            ret += numMembers;
237
0
        }
238
239
0
        return ret;
240
0
    }
241
242
    // Traverse the provided deref chain, including the base, and
243
    // - build a full reflection-granularity name, array size, etc. entry out of it, if it goes down to that granularity
244
    // - recursively expand any variable array index in the middle of that traversal
245
    // - recursively expand what's left at the end if the deref chain did not reach down to reflection granularity
246
    //
247
    // arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
248
    // A value of 0 for arraySize will mean to use the full array's size.
249
    void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
250
                               TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize,
251
                               int topLevelArraySize, int topLevelArrayStride, TStorageQualifier baseStorage, bool active)
252
0
    {
253
        // when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query.
254
        // Broadly:
255
        // * arrays-of-structs always have a [x] suffix.
256
        // * with array-of-struct variables in the root of a buffer block, only ever return [0].
257
        // * otherwise, array suffixes are added whenever we iterate, even if that means expanding out an array.
258
0
        const bool strictArraySuffix = (reflection.options & EShReflectionStrictArraySuffix);
259
260
        // is this variable inside a buffer block. This flag is set back to false after we iterate inside the first array element.
261
0
        bool blockParent = (baseType.getBasicType() == EbtBlock && baseType.getQualifier().storage == EvqBuffer);
262
263
        // process the part of the dereference chain that was explicit in the shader
264
0
        TString name = baseName;
265
0
        const TType* terminalType = &baseType;
266
0
        for (; deref != derefs.end(); ++deref) {
267
0
            TIntermBinary* visitNode = *deref;
268
0
            terminalType = &visitNode->getType();
269
0
            int index;
270
0
            switch (visitNode->getOp()) {
271
0
            case EOpIndexIndirect: {
272
0
                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
273
274
0
                if (topLevelArrayStride == 0)
275
0
                    topLevelArrayStride = stride;
276
277
                // Visit all the indices of this array, and for each one add on the remaining dereferencing
278
0
                for (int i = 0; i < std::max(visitNode->getLeft()->getType().getOuterArraySize(), 1); ++i) {
279
0
                    TString newBaseName = name;
280
0
                    if (terminalType->getBasicType() == EbtBlock) {}
281
0
                    else if (strictArraySuffix && blockParent)
282
0
                        newBaseName.append(TString("[0]"));
283
0
                    else if (strictArraySuffix || baseType.getBasicType() != EbtBlock)
284
0
                        newBaseName.append(TString("[") + String(i) + "]");
285
0
                    TList<TIntermBinary*>::const_iterator nextDeref = deref;
286
0
                    ++nextDeref;
287
0
                    blowUpActiveAggregate(*terminalType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize,
288
0
                                          topLevelArraySize, topLevelArrayStride, baseStorage, active);
289
290
0
                    if (offset >= 0)
291
0
                        offset += stride;
292
0
                }
293
294
                // it was all completed in the recursive calls above
295
0
                return;
296
0
            }
297
0
            case EOpIndexDirect: {
298
0
                int stride = getArrayStride(baseType, visitNode->getLeft()->getType());
299
300
0
                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
301
0
                if (terminalType->getBasicType() == EbtBlock) {}
302
0
                else if (strictArraySuffix && blockParent)
303
0
                    name.append(TString("[0]"));
304
0
                else if (strictArraySuffix || baseType.getBasicType() != EbtBlock) {
305
0
                    name.append(TString("[") + String(index) + "]");
306
307
0
                    if (offset >= 0)
308
0
                        offset += stride * index;
309
0
                }
310
311
0
                if (topLevelArrayStride == 0)
312
0
                    topLevelArrayStride = stride;
313
314
                // expand top-level arrays in blocks with [0] suffix
315
0
                if (topLevelArrayStride != 0 && visitNode->getLeft()->getType().isArray()) {
316
0
                    blockParent = false;
317
0
                }
318
0
                break;
319
0
            }
320
0
            case EOpIndexDirectStruct:
321
0
                index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
322
0
                if (offset >= 0)
323
0
                    offset += intermediate.getOffset(visitNode->getLeft()->getType(), index);
324
0
                if (name.size() > 0)
325
0
                    name.append(".");
326
0
                name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
327
328
                // expand non top-level arrays with [x] suffix
329
0
                if (visitNode->getLeft()->getType().getBasicType() != EbtBlock && terminalType->isArray())
330
0
                {
331
0
                    blockParent = false;
332
0
                }
333
0
                break;
334
0
            default:
335
0
                break;
336
0
            }
337
0
        }
338
339
        // if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
340
0
        if (! isReflectionGranularity(*terminalType)) {
341
            // the base offset of this node, that children are relative to
342
0
            int baseOffset = offset;
343
344
0
            if (terminalType->isArray()) {
345
                // Visit all the indices of this array, and for each one,
346
                // fully explode the remaining aggregate to dereference
347
348
0
                int stride = 0;
349
0
                if (offset >= 0)
350
0
                    stride = getArrayStride(baseType, *terminalType);
351
352
0
                int arrayIterateSize = std::max(terminalType->getOuterArraySize(), 1);
353
354
                // for top-level arrays in blocks, only expand [0] to avoid explosion of items
355
0
                if ((strictArraySuffix && blockParent) ||
356
0
                    ((topLevelArraySize == arrayIterateSize) && (topLevelArrayStride == 0))) {
357
0
                    arrayIterateSize = 1;
358
0
                }
359
360
0
                if (topLevelArrayStride == 0)
361
0
                    topLevelArrayStride = stride;
362
363
0
                for (int i = 0; i < arrayIterateSize; ++i) {
364
0
                    TString newBaseName = name;
365
0
                    if (terminalType->getBasicType() != EbtBlock)
366
0
                        newBaseName.append(TString("[") + String(i) + "]");
367
0
                    TType derefType(*terminalType, 0);
368
0
                    if (offset >= 0)
369
0
                        offset = baseOffset + stride * i;
370
371
0
                    blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
372
0
                                          topLevelArraySize, topLevelArrayStride, baseStorage, active);
373
0
                }
374
0
            } else {
375
                // Visit all members of this aggregate, and for each one,
376
                // fully explode the remaining aggregate to dereference
377
0
                const TTypeList& typeList = *terminalType->getStruct();
378
379
0
                TVector<int> memberOffsets;
380
381
0
                if (baseOffset >= 0) {
382
0
                    memberOffsets.resize(typeList.size());
383
0
                    getOffsets(*terminalType, memberOffsets);
384
0
                }
385
386
0
                for (int i = 0; i < (int)typeList.size(); ++i) {
387
0
                    TString newBaseName = name;
388
0
                    if (newBaseName.size() > 0)
389
0
                        newBaseName.append(".");
390
0
                    newBaseName.append(typeList[i].type->getFieldName());
391
0
                    TType derefType(*terminalType, i);
392
0
                    if (offset >= 0)
393
0
                        offset = baseOffset + memberOffsets[i];
394
395
0
                    int arrayStride = topLevelArrayStride;
396
0
                    if (terminalType->getBasicType() == EbtBlock && terminalType->getQualifier().storage == EvqBuffer &&
397
0
                        derefType.isArray()) {
398
0
                        arrayStride = getArrayStride(baseType, derefType);
399
0
                    }
400
401
0
                    if (topLevelArraySize == -1 && arrayStride == 0 && blockParent)
402
0
                        topLevelArraySize = 1;
403
404
0
                    if (strictArraySuffix && blockParent) {
405
                        // if this member is an array, store the top-level array stride but start the explosion from
406
                        // the inner struct type.
407
0
                        if (derefType.isArray() && derefType.isStruct()) {
408
0
                            newBaseName.append("[0]");
409
0
                            auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0);
410
0
                            blowUpActiveAggregate(TType(derefType, 0), newBaseName, derefs, derefs.end(), memberOffsets[i],
411
0
                                blockIndex, 0, dimSize, arrayStride, terminalType->getQualifier().storage, false);
412
0
                        }
413
0
                        else if (derefType.isArray()) {
414
0
                            auto dimSize = derefType.isUnsizedArray() ? 0 : derefType.getArraySizes()->getDimSize(0);
415
0
                            blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex,
416
0
                                0, dimSize, 0, terminalType->getQualifier().storage, false);
417
0
                        }
418
0
                        else {
419
0
                            blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), memberOffsets[i], blockIndex,
420
0
                                0, 1, 0, terminalType->getQualifier().storage, false);
421
0
                        }
422
0
                    } else {
423
0
                        blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0,
424
0
                                              topLevelArraySize, arrayStride, baseStorage, active);
425
0
                    }
426
0
                }
427
0
            }
428
429
            // it was all completed in the recursive calls above
430
0
            return;
431
0
        }
432
433
0
        if ((reflection.options & EShReflectionBasicArraySuffix) && terminalType->isArray()) {
434
0
            name.append(TString("[0]"));
435
0
        }
436
437
        // Finally, add a full string to the reflection database, and update the array size if necessary.
438
        // If the dereferenced entity to record is an array, compute the size and update the maximum size.
439
440
        // there might not be a final array dereference, it could have been copied as an array object
441
0
        if (arraySize == 0)
442
0
            arraySize = mapToGlArraySize(*terminalType);
443
444
0
        TReflection::TMapIndexToReflection& variables = reflection.GetVariableMapForStorage(baseStorage);
445
446
0
        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
447
0
        if (it == reflection.nameToIndex.end()) {
448
0
            int uniformIndex = (int)variables.size();
449
0
            reflection.nameToIndex[name.c_str()] = uniformIndex;
450
0
            variables.push_back(TObjectReflection(name.c_str(), *terminalType, offset, mapToGlType(*terminalType),
451
0
                                                  arraySize, blockIndex));
452
0
            if (terminalType->isArray()) {
453
0
                variables.back().arrayStride = getArrayStride(baseType, *terminalType);
454
0
                if (topLevelArrayStride == 0)
455
0
                    topLevelArrayStride = variables.back().arrayStride;
456
0
            }
457
458
0
            if ((reflection.options & EShReflectionSeparateBuffers) && terminalType->isAtomic())
459
0
                reflection.atomicCounterUniformIndices.push_back(uniformIndex);
460
461
0
            variables.back().topLevelArraySize = topLevelArraySize;
462
0
            variables.back().topLevelArrayStride = topLevelArrayStride;
463
464
0
            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
465
0
                EShLanguageMask& stages = variables.back().stages;
466
0
                stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
467
0
            }
468
0
        } else {
469
0
            if (arraySize > 1) {
470
0
                int& reflectedArraySize = variables[it->second].size;
471
0
                reflectedArraySize = std::max(arraySize, reflectedArraySize);
472
0
            }
473
474
0
            if ((reflection.options & EShReflectionAllBlockVariables) && active) {
475
0
              EShLanguageMask& stages = variables[it->second].stages;
476
0
              stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
477
0
            }
478
0
        }
479
0
    }
480
481
    // similar to blowUpActiveAggregate, but with simpler rules and no dereferences to follow.
482
    void blowUpIOAggregate(bool input, const TString &baseName, const TType &type)
483
0
    {
484
0
        TString name = baseName;
485
486
        // if the type is still too coarse a granularity, this is still an aggregate to expand, expand it...
487
0
        if (! isReflectionGranularity(type)) {
488
0
            if (type.isArray()) {
489
                // Visit all the indices of this array, and for each one,
490
                // fully explode the remaining aggregate to dereference
491
0
                for (int i = 0; i < std::max(type.getOuterArraySize(), 1); ++i) {
492
0
                    TString newBaseName = name;
493
0
                    newBaseName.append(TString("[") + String(i) + "]");
494
0
                    TType derefType(type, 0);
495
496
0
                    blowUpIOAggregate(input, newBaseName, derefType);
497
0
                }
498
0
            } else {
499
                // Visit all members of this aggregate, and for each one,
500
                // fully explode the remaining aggregate to dereference
501
0
                const TTypeList& typeList = *type.getStruct();
502
503
0
                for (int i = 0; i < (int)typeList.size(); ++i) {
504
                    // A member left out of a block redeclaration, or not available without an
505
                    // extension, is not part of the interface.
506
0
                    if (typeList[i].type->hiddenMember())
507
0
                        continue;
508
0
                    TString newBaseName = name;
509
0
                    if (newBaseName.size() > 0)
510
0
                        newBaseName.append(".");
511
0
                    newBaseName.append(typeList[i].type->getFieldName());
512
0
                    TType derefType(type, i);
513
514
0
                    blowUpIOAggregate(input, newBaseName, derefType);
515
0
                }
516
0
            }
517
518
            // it was all completed in the recursive calls above
519
0
            return;
520
0
        }
521
522
0
        if ((reflection.options & EShReflectionBasicArraySuffix) && type.isArray()) {
523
0
            name.append(TString("[0]"));
524
0
        }
525
526
0
        TReflection::TMapIndexToReflection &ioItems =
527
0
            input ? reflection.indexToPipeInput : reflection.indexToPipeOutput;
528
529
0
        std::string namespacedName = input ? "in " : "out ";
530
0
        namespacedName += name.c_str();
531
532
0
        TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(namespacedName);
533
0
        if (it == reflection.nameToIndex.end()) {
534
0
            reflection.nameToIndex[namespacedName] = (int)ioItems.size();
535
0
            ioItems.push_back(
536
0
                TObjectReflection(name.c_str(), type, 0, mapToGlType(type), mapToGlArraySize(type), 0));
537
538
0
            EShLanguageMask& stages = ioItems.back().stages;
539
0
            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
540
0
        } else {
541
0
            EShLanguageMask& stages = ioItems[it->second].stages;
542
0
            stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
543
0
        }
544
0
    }
545
546
    // Add a uniform dereference where blocks/struct/arrays are involved in the access.
547
    // Handles the situation where the left node is at the correct or too coarse a
548
    // granularity for reflection.  (That is, further dereferences up the tree will be
549
    // skipped.) Earlier dereferences, down the tree, will be handled
550
    // at the same time, and logged to prevent reprocessing as the tree is traversed.
551
    //
552
    // Note: Other things like the following must be caught elsewhere:
553
    //  - a simple non-array, non-struct variable (no dereference even conceivable)
554
    //  - an aggregrate consumed en masse, without a dereference
555
    //
556
    // So, this code is for cases like
557
    //   - a struct/block dereferencing a member (whether the member is array or not)
558
    //   - an array of struct
559
    //   - structs/arrays containing the above
560
    //
561
    void addDereferencedUniform(TIntermBinary* topNode)
562
0
    {
563
        // See if too fine-grained to process (wait to get further down the tree)
564
0
        const TType& leftType = topNode->getLeft()->getType();
565
0
        if ((leftType.isVector() || leftType.isMatrix()) && ! leftType.isArray())
566
0
            return;
567
568
        // We have an array or structure or block dereference, see if it's a uniform
569
        // based dereference (if not, skip it).
570
0
        TIntermSymbol* base = findBase(topNode);
571
0
        if (! base || ! base->getQualifier().isUniformOrBuffer())
572
0
            return;
573
574
        // See if we've already processed this (e.g., in the middle of something
575
        // we did earlier), and if so skip it
576
0
        if (processedDerefs.find(topNode) != processedDerefs.end())
577
0
            return;
578
579
        // Process this uniform dereference
580
581
0
        int offset = -1;
582
0
        int blockIndex = -1;
583
0
        bool anonymous = false;
584
585
        // See if we need to record the block itself
586
0
        bool block = base->getBasicType() == EbtBlock;
587
0
        if (block) {
588
0
            offset = 0;
589
0
            anonymous = IsAnonymous(base->getName());
590
591
0
            const TString& blockName = base->getType().getTypeName();
592
0
            TString baseName;
593
594
0
            if (! anonymous)
595
0
                baseName = blockName;
596
597
0
            blockIndex = addBlockName(blockName, base->getType(), intermediate.getBlockSize(base->getType()));
598
599
0
            if (reflection.options & EShReflectionAllBlockVariables) {
600
                // Use a degenerate (empty) set of dereferences to immediately put as at the end of
601
                // the dereference change expected by blowUpActiveAggregate.
602
0
                TList<TIntermBinary*> derefs;
603
604
                // otherwise - if we're not using strict array suffix rules, or this isn't a block so we are
605
                // expanding root arrays anyway, just start the iteration from the base block type.
606
0
                blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.end(), 0, blockIndex, 0, -1, 0,
607
0
                                          base->getQualifier().storage, false);
608
0
            }
609
0
        }
610
611
        // Process the dereference chain, backward, accumulating the pieces for later forward traversal.
612
        // If the topNode is a reflection-granularity-array dereference, don't include that last dereference.
613
0
        TList<TIntermBinary*> derefs;
614
0
        for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
615
0
            if (isReflectionGranularity(visitNode->getLeft()->getType()))
616
0
                continue;
617
618
0
            derefs.push_front(visitNode);
619
0
            processedDerefs.insert(visitNode);
620
0
        }
621
0
        processedDerefs.insert(base);
622
623
        // See if we have a specific array size to stick to while enumerating the explosion of the aggregate
624
0
        int arraySize = 0;
625
0
        if (isReflectionGranularity(topNode->getLeft()->getType()) && topNode->getLeft()->isArray()) {
626
0
            if (topNode->getOp() == EOpIndexDirect)
627
0
                arraySize = topNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst() + 1;
628
0
        }
629
630
        // Put the dereference chain together, forward
631
0
        TString baseName;
632
0
        if (! anonymous) {
633
0
            if (block)
634
0
                baseName = base->getType().getTypeName();
635
0
            else
636
0
                baseName = base->getName();
637
0
        }
638
0
        blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize, -1, 0,
639
0
                              base->getQualifier().storage, true);
640
0
    }
641
642
    int addBlockName(const TString& name, const TType& type, int size)
643
0
    {
644
0
        int blockIndex = 0;
645
0
        if (type.isArray()) {
646
0
            TType derefType(type, 0);
647
0
            for (int e = 0; e < type.getOuterArraySize(); ++e) {
648
0
                int memberBlockIndex = addBlockName(name + "[" + String(e) + "]", derefType, size);
649
0
                if (e == 0)
650
0
                    blockIndex = memberBlockIndex;
651
0
            }
652
0
        } else {
653
0
            TReflection::TMapIndexToReflection& blocks = reflection.GetBlockMapForStorage(type.getQualifier().storage);
654
655
0
            TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name.c_str());
656
0
            if (reflection.nameToIndex.find(name.c_str()) == reflection.nameToIndex.end()) {
657
0
                blockIndex = (int)blocks.size();
658
0
                reflection.nameToIndex[name.c_str()] = blockIndex;
659
0
                blocks.push_back(TObjectReflection(name.c_str(), type, -1, -1, size, blockIndex));
660
661
0
                blocks.back().numMembers = countAggregateMembers(type);
662
663
0
                if (updateStageMasks) {
664
0
                    EShLanguageMask& stages = blocks.back().stages;
665
0
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
666
0
                }
667
0
            }
668
0
            else {
669
0
                blockIndex = it->second;
670
0
                if (updateStageMasks) {
671
0
                    EShLanguageMask& stages = blocks[blockIndex].stages;
672
0
                    stages = static_cast<EShLanguageMask>(stages | 1 << intermediate.getStage());
673
0
                }
674
0
            }
675
0
        }
676
677
0
        return blockIndex;
678
0
    }
679
680
    // Are we at a level in a dereference chain at which individual active uniform queries are made?
681
    bool isReflectionGranularity(const TType& type)
682
0
    {
683
0
        return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct && !type.isArrayOfArrays();
684
0
    }
685
686
    // For a binary operation indexing into an aggregate, chase down the base of the aggregate.
687
    // Return nullptr if the topology does not fit this situation.
688
    TIntermSymbol* findBase(const TIntermBinary* node)
689
0
    {
690
0
        TIntermSymbol *base = node->getLeft()->getAsSymbolNode();
691
0
        if (base)
692
0
            return base;
693
0
        TIntermBinary* left = node->getLeft()->getAsBinaryNode();
694
0
        if (! left)
695
0
            return nullptr;
696
697
0
        return findBase(left);
698
0
    }
699
700
    //
701
    // Translate a glslang sampler type into the GL API #define number.
702
    //
703
    int mapSamplerToGlType(TSampler sampler)
704
0
    {
705
0
        if (! sampler.image) {
706
            // a sampler...
707
0
            switch (sampler.type) {
708
0
            case EbtFloat:
709
0
                switch ((int)sampler.dim) {
710
0
                case Esd1D:
711
0
                    if (sampler.shadow)
712
0
                        return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW;
713
0
                    else
714
0
                        return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
715
0
                case Esd2D:
716
0
                    if (sampler.ms) {
717
0
                        return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE;
718
0
                    } else {
719
0
                        if (sampler.shadow)
720
0
                            return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW;
721
0
                        else
722
0
                            return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
723
0
                    }
724
0
                case Esd3D:
725
0
                    return GL_SAMPLER_3D;
726
0
                case EsdCube:
727
0
                    if (sampler.shadow)
728
0
                        return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW;
729
0
                    else
730
0
                        return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
731
0
                case EsdRect:
732
0
                    return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
733
0
                case EsdBuffer:
734
0
                    return GL_SAMPLER_BUFFER;
735
0
                default:
736
0
                    return 0;
737
0
                }
738
0
            case EbtFloat16:
739
0
                switch ((int)sampler.dim) {
740
0
                case Esd1D:
741
0
                    if (sampler.shadow)
742
0
                        return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD;
743
0
                    else
744
0
                        return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD;
745
0
                case Esd2D:
746
0
                    if (sampler.ms) {
747
0
                        return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD;
748
0
                    } else {
749
0
                        if (sampler.shadow)
750
0
                            return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD;
751
0
                        else
752
0
                            return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD;
753
0
                    }
754
0
                case Esd3D:
755
0
                    return GL_FLOAT16_SAMPLER_3D_AMD;
756
0
                case EsdCube:
757
0
                    if (sampler.shadow)
758
0
                        return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD;
759
0
                    else
760
0
                        return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD;
761
0
                case EsdRect:
762
0
                    return sampler.shadow ? GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_RECT_AMD;
763
0
                case EsdBuffer:
764
0
                    return GL_FLOAT16_SAMPLER_BUFFER_AMD;
765
0
                default:
766
0
                    return 0;
767
0
                }
768
0
            case EbtInt:
769
0
                switch ((int)sampler.dim) {
770
0
                case Esd1D:
771
0
                    return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D;
772
0
                case Esd2D:
773
0
                    if (sampler.ms)
774
0
                        return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
775
0
                                               : GL_INT_SAMPLER_2D_MULTISAMPLE;
776
0
                    else
777
0
                        return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
778
0
                case Esd3D:
779
0
                    return GL_INT_SAMPLER_3D;
780
0
                case EsdCube:
781
0
                    return sampler.arrayed ? GL_INT_SAMPLER_CUBE_MAP_ARRAY : GL_INT_SAMPLER_CUBE;
782
0
                case EsdRect:
783
0
                    return GL_INT_SAMPLER_2D_RECT;
784
0
                case EsdBuffer:
785
0
                    return GL_INT_SAMPLER_BUFFER;
786
0
                default:
787
0
                    return 0;
788
0
                }
789
0
            case EbtUint:
790
0
                switch ((int)sampler.dim) {
791
0
                case Esd1D:
792
0
                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D;
793
0
                case Esd2D:
794
0
                    if (sampler.ms)
795
0
                        return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY
796
0
                                               : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
797
0
                    else
798
0
                        return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
799
0
                case Esd3D:
800
0
                    return GL_UNSIGNED_INT_SAMPLER_3D;
801
0
                case EsdCube:
802
0
                    return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_SAMPLER_CUBE;
803
0
                case EsdRect:
804
0
                    return GL_UNSIGNED_INT_SAMPLER_2D_RECT;
805
0
                case EsdBuffer:
806
0
                    return GL_UNSIGNED_INT_SAMPLER_BUFFER;
807
0
                default:
808
0
                    return 0;
809
0
                }
810
0
            default:
811
0
                return 0;
812
0
            }
813
0
        } else {
814
            // an image...
815
0
            switch (sampler.type) {
816
0
            case EbtFloat:
817
0
                switch ((int)sampler.dim) {
818
0
                case Esd1D:
819
0
                    return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D;
820
0
                case Esd2D:
821
0
                    if (sampler.ms)
822
0
                        return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE;
823
0
                    else
824
0
                        return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D;
825
0
                case Esd3D:
826
0
                    return GL_IMAGE_3D;
827
0
                case EsdCube:
828
0
                    return sampler.arrayed ? GL_IMAGE_CUBE_MAP_ARRAY : GL_IMAGE_CUBE;
829
0
                case EsdRect:
830
0
                    return GL_IMAGE_2D_RECT;
831
0
                case EsdBuffer:
832
0
                    return GL_IMAGE_BUFFER;
833
0
                default:
834
0
                    return 0;
835
0
                }
836
0
            case EbtFloat16:
837
0
                switch ((int)sampler.dim) {
838
0
                case Esd1D:
839
0
                    return sampler.arrayed ? GL_FLOAT16_IMAGE_1D_ARRAY_AMD : GL_FLOAT16_IMAGE_1D_AMD;
840
0
                case Esd2D:
841
0
                    if (sampler.ms)
842
0
                        return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD;
843
0
                    else
844
0
                        return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD;
845
0
                case Esd3D:
846
0
                    return GL_FLOAT16_IMAGE_3D_AMD;
847
0
                case EsdCube:
848
0
                    return sampler.arrayed ? GL_FLOAT16_IMAGE_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_IMAGE_CUBE_AMD;
849
0
                case EsdRect:
850
0
                    return GL_FLOAT16_IMAGE_2D_RECT_AMD;
851
0
                case EsdBuffer:
852
0
                    return GL_FLOAT16_IMAGE_BUFFER_AMD;
853
0
                default:
854
0
                    return 0;
855
0
                }
856
0
            case EbtInt:
857
0
                switch ((int)sampler.dim) {
858
0
                case Esd1D:
859
0
                    return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D;
860
0
                case Esd2D:
861
0
                    if (sampler.ms)
862
0
                        return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE;
863
0
                    else
864
0
                        return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D;
865
0
                case Esd3D:
866
0
                    return GL_INT_IMAGE_3D;
867
0
                case EsdCube:
868
0
                    return sampler.arrayed ? GL_INT_IMAGE_CUBE_MAP_ARRAY : GL_INT_IMAGE_CUBE;
869
0
                case EsdRect:
870
0
                    return GL_INT_IMAGE_2D_RECT;
871
0
                case EsdBuffer:
872
0
                    return GL_INT_IMAGE_BUFFER;
873
0
                default:
874
0
                    return 0;
875
0
                }
876
0
            case EbtUint:
877
0
                switch ((int)sampler.dim) {
878
0
                case Esd1D:
879
0
                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D;
880
0
                case Esd2D:
881
0
                    if (sampler.ms)
882
0
                        return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY
883
0
                                               : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
884
0
                    else
885
0
                        return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
886
0
                case Esd3D:
887
0
                    return GL_UNSIGNED_INT_IMAGE_3D;
888
0
                case EsdCube:
889
0
                    return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_IMAGE_CUBE;
890
0
                case EsdRect:
891
0
                    return GL_UNSIGNED_INT_IMAGE_2D_RECT;
892
0
                case EsdBuffer:
893
0
                    return GL_UNSIGNED_INT_IMAGE_BUFFER;
894
0
                default:
895
0
                    return 0;
896
0
                }
897
0
            default:
898
0
                return 0;
899
0
            }
900
0
        }
901
0
    }
902
903
    //
904
    // Translate a glslang type into the GL API #define number.
905
    // Ignores arrayness.
906
    //
907
    int mapToGlType(const TType& type)
908
0
    {
909
0
        switch (type.getBasicType()) {
910
0
        case EbtSampler:
911
0
            return mapSamplerToGlType(type.getSampler());
912
0
        case EbtStruct:
913
0
        case EbtBlock:
914
0
        case EbtVoid:
915
0
            return 0;
916
0
        default:
917
0
            break;
918
0
        }
919
920
0
        if (type.isVector()) {
921
0
            int offset = type.getVectorSize() - 2;
922
0
            switch (type.getBasicType()) {
923
0
            case EbtFloat:      return GL_FLOAT_VEC2                  + offset;
924
0
            case EbtDouble:     return GL_DOUBLE_VEC2                 + offset;
925
0
            case EbtFloat16:    return GL_FLOAT16_VEC2_NV             + offset;
926
0
            case EbtInt:        return GL_INT_VEC2                    + offset;
927
0
            case EbtUint:       return GL_UNSIGNED_INT_VEC2           + offset;
928
0
            case EbtInt64:      return GL_INT64_VEC2_ARB              + offset;
929
0
            case EbtUint64:     return GL_UNSIGNED_INT64_VEC2_ARB     + offset;
930
0
            case EbtBool:       return GL_BOOL_VEC2                   + offset;
931
0
            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset;
932
0
            default:            return 0;
933
0
            }
934
0
        }
935
0
        if (type.isMatrix()) {
936
0
            switch (type.getBasicType()) {
937
0
            case EbtFloat:
938
0
                switch (type.getMatrixCols()) {
939
0
                case 2:
940
0
                    switch (type.getMatrixRows()) {
941
0
                    case 2:    return GL_FLOAT_MAT2;
942
0
                    case 3:    return GL_FLOAT_MAT2x3;
943
0
                    case 4:    return GL_FLOAT_MAT2x4;
944
0
                    default:   return 0;
945
0
                    }
946
0
                case 3:
947
0
                    switch (type.getMatrixRows()) {
948
0
                    case 2:    return GL_FLOAT_MAT3x2;
949
0
                    case 3:    return GL_FLOAT_MAT3;
950
0
                    case 4:    return GL_FLOAT_MAT3x4;
951
0
                    default:   return 0;
952
0
                    }
953
0
                case 4:
954
0
                    switch (type.getMatrixRows()) {
955
0
                    case 2:    return GL_FLOAT_MAT4x2;
956
0
                    case 3:    return GL_FLOAT_MAT4x3;
957
0
                    case 4:    return GL_FLOAT_MAT4;
958
0
                    default:   return 0;
959
0
                    }
960
0
                default: return 0;
961
0
                }
962
0
            case EbtDouble:
963
0
                switch (type.getMatrixCols()) {
964
0
                case 2:
965
0
                    switch (type.getMatrixRows()) {
966
0
                    case 2:    return GL_DOUBLE_MAT2;
967
0
                    case 3:    return GL_DOUBLE_MAT2x3;
968
0
                    case 4:    return GL_DOUBLE_MAT2x4;
969
0
                    default:   return 0;
970
0
                    }
971
0
                case 3:
972
0
                    switch (type.getMatrixRows()) {
973
0
                    case 2:    return GL_DOUBLE_MAT3x2;
974
0
                    case 3:    return GL_DOUBLE_MAT3;
975
0
                    case 4:    return GL_DOUBLE_MAT3x4;
976
0
                    default:   return 0;
977
0
                    }
978
0
                case 4:
979
0
                    switch (type.getMatrixRows()) {
980
0
                    case 2:    return GL_DOUBLE_MAT4x2;
981
0
                    case 3:    return GL_DOUBLE_MAT4x3;
982
0
                    case 4:    return GL_DOUBLE_MAT4;
983
0
                    default:   return 0;
984
0
                    }
985
0
                default: return 0;
986
0
                }
987
0
            case EbtFloat16:
988
0
                switch (type.getMatrixCols()) {
989
0
                case 2:
990
0
                    switch (type.getMatrixRows()) {
991
0
                    case 2:    return GL_FLOAT16_MAT2_AMD;
992
0
                    case 3:    return GL_FLOAT16_MAT2x3_AMD;
993
0
                    case 4:    return GL_FLOAT16_MAT2x4_AMD;
994
0
                    default:   return 0;
995
0
                    }
996
0
                case 3:
997
0
                    switch (type.getMatrixRows()) {
998
0
                    case 2:    return GL_FLOAT16_MAT3x2_AMD;
999
0
                    case 3:    return GL_FLOAT16_MAT3_AMD;
1000
0
                    case 4:    return GL_FLOAT16_MAT3x4_AMD;
1001
0
                    default:   return 0;
1002
0
                    }
1003
0
                case 4:
1004
0
                    switch (type.getMatrixRows()) {
1005
0
                    case 2:    return GL_FLOAT16_MAT4x2_AMD;
1006
0
                    case 3:    return GL_FLOAT16_MAT4x3_AMD;
1007
0
                    case 4:    return GL_FLOAT16_MAT4_AMD;
1008
0
                    default:   return 0;
1009
0
                    }
1010
0
                default: return 0;
1011
0
                }
1012
0
            default:
1013
0
                return 0;
1014
0
            }
1015
0
        }
1016
0
        if (type.getVectorSize() == 1) {
1017
0
            switch (type.getBasicType()) {
1018
0
            case EbtFloat:      return GL_FLOAT;
1019
0
            case EbtDouble:     return GL_DOUBLE;
1020
0
            case EbtFloat16:    return GL_FLOAT16_NV;
1021
0
            case EbtInt:        return GL_INT;
1022
0
            case EbtUint:       return GL_UNSIGNED_INT;
1023
0
            case EbtInt64:      return GL_INT64_ARB;
1024
0
            case EbtUint64:     return GL_UNSIGNED_INT64_ARB;
1025
0
            case EbtBool:       return GL_BOOL;
1026
0
            case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER;
1027
0
            default:            return 0;
1028
0
            }
1029
0
        }
1030
1031
0
        return 0;
1032
0
    }
1033
1034
    int mapToGlArraySize(const TType& type)
1035
0
    {
1036
0
        return type.isArray() ? type.getOuterArraySize() : 1;
1037
0
    }
1038
1039
    const TIntermediate& intermediate;
1040
    TReflection& reflection;
1041
    std::set<const TIntermNode*> processedDerefs;
1042
    bool updateStageMasks;
1043
1044
protected:
1045
    TReflectionTraverser(TReflectionTraverser&);
1046
    TReflectionTraverser& operator=(TReflectionTraverser&);
1047
};
1048
1049
//
1050
// Implement the traversal functions of interest.
1051
//
1052
1053
// To catch dereferenced aggregates that must be reflected.
1054
// This catches them at the highest level possible in the tree.
1055
bool TReflectionTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
1056
0
{
1057
0
    switch (node->getOp()) {
1058
0
    case EOpIndexDirect:
1059
0
    case EOpIndexIndirect:
1060
0
    case EOpIndexDirectStruct:
1061
0
        addDereferencedUniform(node);
1062
0
        break;
1063
0
    default:
1064
0
        break;
1065
0
    }
1066
1067
    // still need to visit everything below, which could contain sub-expressions
1068
    // containing different uniforms
1069
0
    return true;
1070
0
}
1071
1072
// To reflect non-dereferenced objects.
1073
void TReflectionTraverser::visitSymbol(TIntermSymbol* base)
1074
0
{
1075
0
    if (base->getQualifier().storage == EvqUniform) {
1076
0
        if (base->getBasicType() == EbtBlock) {
1077
0
            if (reflection.options & EShReflectionSharedStd140UBO) {
1078
0
                addUniform(*base);
1079
0
            }
1080
0
        } else {
1081
0
            addUniform(*base);
1082
0
        }
1083
0
    }
1084
1085
    // #TODO add std140/layout active rules for ssbo, same with ubo.
1086
    // Storage buffer blocks will be collected and expanding in this part.
1087
0
    if((reflection.options & EShReflectionSharedStd140SSBO) &&
1088
0
       (base->getQualifier().storage == EvqBuffer && base->getBasicType() == EbtBlock &&
1089
0
        (base->getQualifier().layoutPacking == ElpStd140 || base->getQualifier().layoutPacking == ElpShared)))
1090
0
        addUniform(*base);
1091
1092
0
    if ((intermediate.getStage() == reflection.firstStage && base->getQualifier().isPipeInput()) ||
1093
0
        (intermediate.getStage() == reflection.lastStage && base->getQualifier().isPipeOutput()))
1094
0
        addPipeIOVariable(*base);
1095
0
}
1096
1097
//
1098
// Implement TObjectReflection methods.
1099
//
1100
1101
TObjectReflection::TObjectReflection(const std::string &pName, const TType &pType, int pOffset, int pGLDefineType,
1102
                                     int pSize, int pIndex)
1103
0
    : name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex), counterIndex(-1),
1104
0
      numMembers(-1), arrayStride(0), topLevelArrayStride(0), stages(EShLanguageMask(0)), type(pType.clone())
1105
0
{
1106
0
}
1107
1108
int TObjectReflection::getBinding() const
1109
0
{
1110
0
    if (type == nullptr || !type->getQualifier().hasBinding())
1111
0
        return -1;
1112
0
    return type->getQualifier().layoutBinding;
1113
0
}
1114
1115
void TObjectReflection::dump() const
1116
0
{
1117
0
    printf("%s: offset %d, type %x, size %d, index %d, binding %d, stages %d", name.c_str(), offset, glDefineType, size,
1118
0
           index, getBinding(), stages);
1119
1120
0
    if (counterIndex != -1)
1121
0
        printf(", counter %d", counterIndex);
1122
1123
0
    if (numMembers != -1)
1124
0
        printf(", numMembers %d", numMembers);
1125
1126
0
    if (arrayStride != 0)
1127
0
        printf(", arrayStride %d", arrayStride);
1128
1129
0
    if (topLevelArrayStride != 0)
1130
0
        printf(", topLevelArrayStride %d", topLevelArrayStride);
1131
1132
0
    printf("\n");
1133
0
}
1134
1135
//
1136
// Implement TReflection methods.
1137
//
1138
1139
// Track any required attribute reflection, such as compute shader numthreads.
1140
//
1141
void TReflection::buildAttributeReflection(EShLanguage stage, const TIntermediate& intermediate)
1142
0
{
1143
0
    if (stage == EShLangCompute) {
1144
        // Remember thread dimensions
1145
0
        for (int dim=0; dim<3; ++dim) {
1146
0
            localSize[dim] = intermediate.getLocalSize(dim);
1147
0
            tileShadingRateQCOM[dim] = intermediate.getTileShadingRateQCOM(dim);
1148
0
        }
1149
0
    }
1150
0
}
1151
1152
// build counter block index associations for buffers
1153
void TReflection::buildCounterIndices(const TIntermediate& intermediate)
1154
0
{
1155
0
#ifdef ENABLE_HLSL
1156
    // search for ones that have counters
1157
0
    for (int i = 0; i < int(indexToUniformBlock.size()); ++i) {
1158
0
        const TString counterName(intermediate.addCounterBufferName(indexToUniformBlock[i].name).c_str());
1159
0
        const int index = getIndex(counterName);
1160
1161
0
        if (index >= 0)
1162
0
            indexToUniformBlock[i].counterIndex = index;
1163
0
    }
1164
#else
1165
    (void)intermediate;
1166
#endif
1167
0
}
1168
1169
// build Shader Stages mask for all uniforms
1170
void TReflection::buildUniformStageMask(const TIntermediate& intermediate)
1171
0
{
1172
0
    if (options & EShReflectionAllBlockVariables)
1173
0
        return;
1174
1175
0
    for (int i = 0; i < int(indexToUniform.size()); ++i) {
1176
0
        indexToUniform[i].stages = static_cast<EShLanguageMask>(indexToUniform[i].stages | 1 << intermediate.getStage());
1177
0
    }
1178
1179
0
    for (int i = 0; i < int(indexToBufferVariable.size()); ++i) {
1180
0
        indexToBufferVariable[i].stages =
1181
0
            static_cast<EShLanguageMask>(indexToBufferVariable[i].stages | 1 << intermediate.getStage());
1182
0
    }
1183
0
}
1184
1185
// Merge live symbols from 'intermediate' into the existing reflection database.
1186
//
1187
// Returns false if the input is too malformed to do this.
1188
bool TReflection::addStage(EShLanguage stage, const TIntermediate& intermediate)
1189
0
{
1190
0
    if (intermediate.getTreeRoot() == nullptr ||
1191
0
        intermediate.getNumEntryPoints() != 1 ||
1192
0
        intermediate.isRecursive())
1193
0
        return false;
1194
1195
0
    buildAttributeReflection(stage, intermediate);
1196
1197
0
    TReflectionTraverser it(intermediate, *this);
1198
1199
0
    for (auto& sequnence : intermediate.getTreeRoot()->getAsAggregate()->getSequence()) {
1200
0
        if (sequnence->getAsAggregate() != nullptr) {
1201
0
            if (sequnence->getAsAggregate()->getOp() == glslang::EOpLinkerObjects) {
1202
0
                it.updateStageMasks = false;
1203
0
                TIntermAggregate* linkerObjects = sequnence->getAsAggregate();
1204
0
                for (auto& sequnence : linkerObjects->getSequence()) {
1205
0
                    auto pNode = sequnence->getAsSymbolNode();
1206
0
                    if (pNode != nullptr) {
1207
0
                        if ((pNode->getQualifier().storage == EvqUniform &&
1208
0
                            (options & EShReflectionSharedStd140UBO)) ||
1209
0
                           (pNode->getQualifier().storage == EvqBuffer &&
1210
0
                            (options & EShReflectionSharedStd140SSBO))) {
1211
                            // collect std140 and shared uniform block form AST
1212
0
                            if ((pNode->getBasicType() == EbtBlock) &&
1213
0
                                ((pNode->getQualifier().layoutPacking == ElpStd140) ||
1214
0
                                 (pNode->getQualifier().layoutPacking == ElpShared))) {
1215
0
                                   pNode->traverse(&it);
1216
0
                            }
1217
0
                        }
1218
0
                        else if ((options & EShReflectionAllIOVariables) &&
1219
0
                            (pNode->getQualifier().isPipeInput() || pNode->getQualifier().isPipeOutput()))
1220
0
                        {
1221
0
                            pNode->traverse(&it);
1222
0
                        }
1223
0
                    }
1224
0
                }
1225
0
            } else {
1226
                // This traverser will travers all function in AST.
1227
                // If we want reflect uncalled function, we need set linke message EShMsgKeepUncalled.
1228
                // When EShMsgKeepUncalled been set to true, all function will be keep in AST, even it is a uncalled function.
1229
                // This will keep some uniform variables in reflection, if those uniform variables is used in these uncalled function.
1230
                //
1231
                // If we just want reflect only live node, we can use a default link message or set EShMsgKeepUncalled false.
1232
                // When linke message not been set EShMsgKeepUncalled, linker won't keep uncalled function in AST.
1233
                // So, travers all function node can equivalent to travers live function.
1234
0
                it.updateStageMasks = true;
1235
0
                sequnence->getAsAggregate()->traverse(&it);
1236
0
            }
1237
0
        }
1238
0
    }
1239
0
    it.updateStageMasks = true;
1240
1241
0
    buildCounterIndices(intermediate);
1242
0
    buildUniformStageMask(intermediate);
1243
1244
0
    return true;
1245
0
}
1246
1247
void TReflection::dump()
1248
0
{
1249
0
    printf("Uniform reflection:\n");
1250
0
    for (size_t i = 0; i < indexToUniform.size(); ++i)
1251
0
        indexToUniform[i].dump();
1252
0
    printf("\n");
1253
1254
0
    printf("Uniform block reflection:\n");
1255
0
    for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
1256
0
        indexToUniformBlock[i].dump();
1257
0
    printf("\n");
1258
1259
0
    printf("Buffer variable reflection:\n");
1260
0
    for (size_t i = 0; i < indexToBufferVariable.size(); ++i)
1261
0
      indexToBufferVariable[i].dump();
1262
0
    printf("\n");
1263
1264
0
    printf("Buffer block reflection:\n");
1265
0
    for (size_t i = 0; i < indexToBufferBlock.size(); ++i)
1266
0
      indexToBufferBlock[i].dump();
1267
0
    printf("\n");
1268
1269
0
    printf("Pipeline input reflection:\n");
1270
0
    for (size_t i = 0; i < indexToPipeInput.size(); ++i)
1271
0
        indexToPipeInput[i].dump();
1272
0
    printf("\n");
1273
1274
0
    printf("Pipeline output reflection:\n");
1275
0
    for (size_t i = 0; i < indexToPipeOutput.size(); ++i)
1276
0
        indexToPipeOutput[i].dump();
1277
0
    printf("\n");
1278
1279
0
    static const char* axis[] = { "X", "Y", "Z" };
1280
0
    if (getLocalSize(0) > 1) {
1281
0
        for (int dim=0; dim<3; ++dim)
1282
0
            if (getLocalSize(dim) > 1)
1283
0
                printf("Local size %s: %u\n", axis[dim], getLocalSize(dim));
1284
1285
0
        printf("\n");
1286
0
    }
1287
1288
0
    if (getTileShadingRateQCOM(0) > 1 || getTileShadingRateQCOM(1) > 1) {
1289
0
        for (int dim=0; dim<3; ++dim)
1290
0
            printf("Tile shading rate QCOM %s: %u\n", axis[dim], getTileShadingRateQCOM(dim));
1291
0
        printf("\n");
1292
0
    }
1293
1294
    // printf("Live names\n");
1295
    // for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
1296
    //    printf("%s: %d\n", it->first.c_str(), it->second);
1297
    // printf("\n");
1298
0
}
1299
1300
} // end namespace glslang