Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/compiler/translator/CollectVariables.cpp
1693 views
1
//
2
// Copyright 2002 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
5
//
6
// CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
7
8
#include "compiler/translator/CollectVariables.h"
9
10
#include "angle_gl.h"
11
#include "common/utilities.h"
12
#include "compiler/translator/HashNames.h"
13
#include "compiler/translator/SymbolTable.h"
14
#include "compiler/translator/tree_util/IntermTraverse.h"
15
#include "compiler/translator/util.h"
16
17
namespace sh
18
{
19
20
namespace
21
{
22
23
BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
24
{
25
switch (blockStorage)
26
{
27
case EbsPacked:
28
return BLOCKLAYOUT_PACKED;
29
case EbsShared:
30
return BLOCKLAYOUT_SHARED;
31
case EbsStd140:
32
return BLOCKLAYOUT_STD140;
33
case EbsStd430:
34
return BLOCKLAYOUT_STD430;
35
default:
36
UNREACHABLE();
37
return BLOCKLAYOUT_SHARED;
38
}
39
}
40
41
BlockType GetBlockType(TQualifier qualifier)
42
{
43
switch (qualifier)
44
{
45
case EvqUniform:
46
return BlockType::BLOCK_UNIFORM;
47
case EvqBuffer:
48
return BlockType::BLOCK_BUFFER;
49
default:
50
UNREACHABLE();
51
return BlockType::BLOCK_UNIFORM;
52
}
53
}
54
55
template <class VarT>
56
VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)
57
{
58
// TODO(zmo): optimize this function.
59
for (size_t ii = 0; ii < infoList->size(); ++ii)
60
{
61
if (name == (*infoList)[ii].name)
62
return &((*infoList)[ii]);
63
}
64
65
return nullptr;
66
}
67
68
void MarkActive(ShaderVariable *variable)
69
{
70
if (!variable->active)
71
{
72
if (variable->isStruct())
73
{
74
// Conservatively assume all fields are statically used as well.
75
for (auto &field : variable->fields)
76
{
77
MarkActive(&field);
78
}
79
}
80
variable->staticUse = true;
81
variable->active = true;
82
}
83
}
84
85
ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
86
const TInterfaceBlock *interfaceBlock,
87
std::vector<InterfaceBlock> *infoList)
88
{
89
ASSERT(interfaceBlock);
90
InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
91
ASSERT(namedBlock);
92
93
// Set static use on the parent interface block here
94
namedBlock->staticUse = true;
95
namedBlock->active = true;
96
return FindVariable(name, &namedBlock->fields);
97
}
98
99
ShaderVariable *FindShaderIOBlockVariable(const ImmutableString &blockName,
100
std::vector<ShaderVariable> *infoList)
101
{
102
for (size_t index = 0; index < infoList->size(); ++index)
103
{
104
if (blockName == (*infoList)[index].structOrBlockName)
105
return &(*infoList)[index];
106
}
107
108
return nullptr;
109
}
110
111
// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
112
// shared data and interface blocks.
113
class CollectVariablesTraverser : public TIntermTraverser
114
{
115
public:
116
CollectVariablesTraverser(std::vector<ShaderVariable> *attribs,
117
std::vector<ShaderVariable> *outputVariables,
118
std::vector<ShaderVariable> *uniforms,
119
std::vector<ShaderVariable> *inputVaryings,
120
std::vector<ShaderVariable> *outputVaryings,
121
std::vector<ShaderVariable> *sharedVariables,
122
std::vector<InterfaceBlock> *uniformBlocks,
123
std::vector<InterfaceBlock> *shaderStorageBlocks,
124
ShHashFunction64 hashFunction,
125
TSymbolTable *symbolTable,
126
GLenum shaderType,
127
const TExtensionBehavior &extensionBehavior,
128
const ShBuiltInResources &resources,
129
int tessControlShaderOutputVertices);
130
131
bool visitGlobalQualifierDeclaration(Visit visit,
132
TIntermGlobalQualifierDeclaration *node) override;
133
void visitSymbol(TIntermSymbol *symbol) override;
134
bool visitDeclaration(Visit, TIntermDeclaration *node) override;
135
bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
136
137
private:
138
std::string getMappedName(const TSymbol *symbol) const;
139
140
void setFieldOrVariableProperties(const TType &type,
141
bool staticUse,
142
bool isShaderIOBlock,
143
bool isPatch,
144
ShaderVariable *variableOut) const;
145
void setFieldProperties(const TType &type,
146
const ImmutableString &name,
147
bool staticUse,
148
bool isShaderIOBlock,
149
bool isPatch,
150
ShaderVariable *variableOut) const;
151
void setCommonVariableProperties(const TType &type,
152
const TVariable &variable,
153
ShaderVariable *variableOut) const;
154
155
ShaderVariable recordAttribute(const TIntermSymbol &variable) const;
156
ShaderVariable recordOutputVariable(const TIntermSymbol &variable) const;
157
ShaderVariable recordVarying(const TIntermSymbol &variable) const;
158
void recordInterfaceBlock(const char *instanceName,
159
const TType &interfaceBlockType,
160
InterfaceBlock *interfaceBlock) const;
161
ShaderVariable recordUniform(const TIntermSymbol &variable) const;
162
163
void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
164
165
void recordBuiltInVaryingUsed(const TVariable &variable,
166
bool *addedFlag,
167
std::vector<ShaderVariable> *varyings);
168
void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
169
void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
170
InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
171
172
std::vector<ShaderVariable> *mAttribs;
173
std::vector<ShaderVariable> *mOutputVariables;
174
std::vector<ShaderVariable> *mUniforms;
175
std::vector<ShaderVariable> *mInputVaryings;
176
std::vector<ShaderVariable> *mOutputVaryings;
177
std::vector<ShaderVariable> *mSharedVariables;
178
std::vector<InterfaceBlock> *mUniformBlocks;
179
std::vector<InterfaceBlock> *mShaderStorageBlocks;
180
181
std::map<std::string, ShaderVariable *> mInterfaceBlockFields;
182
183
// Shader uniforms
184
bool mDepthRangeAdded;
185
bool mNumSamplesAdded;
186
187
// Compute Shader builtins
188
bool mNumWorkGroupsAdded;
189
bool mWorkGroupIDAdded;
190
bool mLocalInvocationIDAdded;
191
bool mGlobalInvocationIDAdded;
192
bool mLocalInvocationIndexAdded;
193
194
// Vertex Shader builtins
195
bool mInstanceIDAdded;
196
bool mVertexIDAdded;
197
bool mPointSizeAdded;
198
bool mDrawIDAdded;
199
200
// Vertex Shader and Geometry Shader builtins
201
bool mPositionAdded;
202
bool mClipDistanceAdded;
203
bool mCullDistanceAdded;
204
205
// Fragment Shader builtins
206
bool mPointCoordAdded;
207
bool mFrontFacingAdded;
208
bool mHelperInvocationAdded;
209
bool mFragCoordAdded;
210
bool mLastFragDataAdded;
211
bool mFragColorAdded;
212
bool mFragDataAdded;
213
bool mFragDepthAdded;
214
bool mSecondaryFragColorEXTAdded;
215
bool mSecondaryFragDataEXTAdded;
216
bool mSampleIDAdded;
217
bool mSamplePositionAdded;
218
bool mSampleMaskAdded;
219
bool mSampleMaskInAdded;
220
221
// Geometry and Tessellation Shader builtins
222
bool mPerVertexInAdded;
223
bool mPerVertexOutAdded;
224
225
// Geometry Shader builtins
226
bool mPrimitiveIDInAdded;
227
bool mInvocationIDAdded;
228
229
// Geometry Shader and Fragment Shader builtins
230
bool mPrimitiveIDAdded;
231
bool mLayerAdded;
232
233
// Shared memory variables
234
bool mSharedVariableAdded;
235
236
// Tessellation Shader builtins
237
bool mPatchVerticesInAdded;
238
bool mTessLevelOuterAdded;
239
bool mTessLevelInnerAdded;
240
bool mBoundingBoxEXTAdded;
241
bool mTessCoordAdded;
242
const int mTessControlShaderOutputVertices;
243
244
ShHashFunction64 mHashFunction;
245
246
GLenum mShaderType;
247
const TExtensionBehavior &mExtensionBehavior;
248
const ShBuiltInResources &mResources;
249
};
250
251
CollectVariablesTraverser::CollectVariablesTraverser(
252
std::vector<sh::ShaderVariable> *attribs,
253
std::vector<sh::ShaderVariable> *outputVariables,
254
std::vector<sh::ShaderVariable> *uniforms,
255
std::vector<sh::ShaderVariable> *inputVaryings,
256
std::vector<sh::ShaderVariable> *outputVaryings,
257
std::vector<sh::ShaderVariable> *sharedVariables,
258
std::vector<sh::InterfaceBlock> *uniformBlocks,
259
std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
260
ShHashFunction64 hashFunction,
261
TSymbolTable *symbolTable,
262
GLenum shaderType,
263
const TExtensionBehavior &extensionBehavior,
264
const ShBuiltInResources &resources,
265
int tessControlShaderOutputVertices)
266
: TIntermTraverser(true, false, false, symbolTable),
267
mAttribs(attribs),
268
mOutputVariables(outputVariables),
269
mUniforms(uniforms),
270
mInputVaryings(inputVaryings),
271
mOutputVaryings(outputVaryings),
272
mSharedVariables(sharedVariables),
273
mUniformBlocks(uniformBlocks),
274
mShaderStorageBlocks(shaderStorageBlocks),
275
mDepthRangeAdded(false),
276
mNumSamplesAdded(false),
277
mNumWorkGroupsAdded(false),
278
mWorkGroupIDAdded(false),
279
mLocalInvocationIDAdded(false),
280
mGlobalInvocationIDAdded(false),
281
mLocalInvocationIndexAdded(false),
282
mInstanceIDAdded(false),
283
mVertexIDAdded(false),
284
mPointSizeAdded(false),
285
mDrawIDAdded(false),
286
mPositionAdded(false),
287
mClipDistanceAdded(false),
288
mCullDistanceAdded(false),
289
mPointCoordAdded(false),
290
mFrontFacingAdded(false),
291
mHelperInvocationAdded(false),
292
mFragCoordAdded(false),
293
mLastFragDataAdded(false),
294
mFragColorAdded(false),
295
mFragDataAdded(false),
296
mFragDepthAdded(false),
297
mSecondaryFragColorEXTAdded(false),
298
mSecondaryFragDataEXTAdded(false),
299
mSampleIDAdded(false),
300
mSamplePositionAdded(false),
301
mSampleMaskAdded(false),
302
mSampleMaskInAdded(false),
303
mPerVertexInAdded(false),
304
mPerVertexOutAdded(false),
305
mPrimitiveIDInAdded(false),
306
mInvocationIDAdded(false),
307
mPrimitiveIDAdded(false),
308
mLayerAdded(false),
309
mSharedVariableAdded(false),
310
mPatchVerticesInAdded(false),
311
mTessLevelOuterAdded(false),
312
mTessLevelInnerAdded(false),
313
mBoundingBoxEXTAdded(false),
314
mTessCoordAdded(false),
315
mTessControlShaderOutputVertices(tessControlShaderOutputVertices),
316
mHashFunction(hashFunction),
317
mShaderType(shaderType),
318
mExtensionBehavior(extensionBehavior),
319
mResources(resources)
320
{}
321
322
std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
323
{
324
return HashName(symbol, mHashFunction, nullptr).data();
325
}
326
327
void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
328
ShaderVariable *info)
329
{
330
const TType &type = variable.getType();
331
332
info->name = variable.name().data();
333
info->mappedName = variable.name().data();
334
335
bool isShaderIOBlock =
336
IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr;
337
bool isPatch = type.getQualifier() == EvqTessLevelInner ||
338
type.getQualifier() == EvqTessLevelOuter ||
339
type.getQualifier() == EvqBoundingBoxEXT;
340
341
setFieldOrVariableProperties(type, true, isShaderIOBlock, isPatch, info);
342
}
343
344
void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
345
bool *addedFlag,
346
std::vector<ShaderVariable> *varyings)
347
{
348
ASSERT(varyings);
349
if (!(*addedFlag))
350
{
351
ShaderVariable info;
352
setBuiltInInfoFromSymbol(variable, &info);
353
info.active = true;
354
info.isInvariant = mSymbolTable->isVaryingInvariant(variable);
355
356
varyings->push_back(info);
357
(*addedFlag) = true;
358
}
359
}
360
361
void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
362
bool *addedFlag)
363
{
364
if (!(*addedFlag))
365
{
366
ShaderVariable info;
367
setBuiltInInfoFromSymbol(variable, &info);
368
info.active = true;
369
mOutputVariables->push_back(info);
370
(*addedFlag) = true;
371
}
372
}
373
374
void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
375
bool *addedFlag)
376
{
377
if (!(*addedFlag))
378
{
379
ShaderVariable info;
380
setBuiltInInfoFromSymbol(variable, &info);
381
info.active = true;
382
info.location = -1;
383
mAttribs->push_back(info);
384
(*addedFlag) = true;
385
}
386
}
387
388
bool CollectVariablesTraverser::visitGlobalQualifierDeclaration(
389
Visit visit,
390
TIntermGlobalQualifierDeclaration *node)
391
{
392
// We should not mark variables as active just based on an invariant/precise declaration, so we
393
// don't traverse the symbols declared invariant.
394
return false;
395
}
396
397
// We want to check whether a uniform/varying is active because we need to skip updating inactive
398
// ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
399
// and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
400
void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
401
{
402
ASSERT(symbol != nullptr);
403
404
if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
405
symbol->variable().symbolType() == SymbolType::Empty)
406
{
407
// Internal variables or nameless variables are not collected.
408
return;
409
}
410
411
ShaderVariable *var = nullptr;
412
413
const ImmutableString &symbolName = symbol->getName();
414
415
// Check the qualifier from the variable, not from the symbol node. The node may have a
416
// different qualifier if it's the result of a folded ternary node.
417
TQualifier qualifier = symbol->variable().getType().getQualifier();
418
const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
419
420
if (IsVaryingIn(qualifier))
421
{
422
if (interfaceBlock)
423
{
424
var = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
425
}
426
else
427
{
428
var = FindVariable(symbolName, mInputVaryings);
429
}
430
}
431
else if (IsVaryingOut(qualifier))
432
{
433
if (interfaceBlock)
434
{
435
var = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
436
}
437
else
438
{
439
var = FindVariable(symbolName, mOutputVaryings);
440
}
441
}
442
else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
443
{
444
UNREACHABLE();
445
}
446
else if (symbolName == "gl_DepthRange")
447
{
448
ASSERT(qualifier == EvqUniform);
449
450
if (!mDepthRangeAdded)
451
{
452
ShaderVariable info;
453
const char kName[] = "gl_DepthRange";
454
info.name = kName;
455
info.mappedName = kName;
456
info.type = GL_NONE;
457
info.precision = GL_NONE;
458
info.staticUse = true;
459
info.active = true;
460
461
ShaderVariable nearInfo(GL_FLOAT);
462
const char kNearName[] = "near";
463
nearInfo.name = kNearName;
464
nearInfo.mappedName = kNearName;
465
nearInfo.precision = GL_HIGH_FLOAT;
466
nearInfo.staticUse = true;
467
nearInfo.active = true;
468
469
ShaderVariable farInfo(GL_FLOAT);
470
const char kFarName[] = "far";
471
farInfo.name = kFarName;
472
farInfo.mappedName = kFarName;
473
farInfo.precision = GL_HIGH_FLOAT;
474
farInfo.staticUse = true;
475
farInfo.active = true;
476
477
ShaderVariable diffInfo(GL_FLOAT);
478
const char kDiffName[] = "diff";
479
diffInfo.name = kDiffName;
480
diffInfo.mappedName = kDiffName;
481
diffInfo.precision = GL_HIGH_FLOAT;
482
diffInfo.staticUse = true;
483
diffInfo.active = true;
484
485
info.fields.push_back(nearInfo);
486
info.fields.push_back(farInfo);
487
info.fields.push_back(diffInfo);
488
489
mUniforms->push_back(info);
490
mDepthRangeAdded = true;
491
}
492
}
493
else if (symbolName == "gl_NumSamples")
494
{
495
ASSERT(qualifier == EvqUniform);
496
497
if (!mNumSamplesAdded)
498
{
499
ShaderVariable info;
500
const char kName[] = "gl_NumSamples";
501
info.name = kName;
502
info.mappedName = kName;
503
info.type = GL_INT;
504
info.precision = GL_LOW_INT;
505
info.staticUse = true;
506
info.active = true;
507
508
mUniforms->push_back(info);
509
mNumSamplesAdded = true;
510
}
511
}
512
else
513
{
514
switch (qualifier)
515
{
516
case EvqAttribute:
517
case EvqVertexIn:
518
var = FindVariable(symbolName, mAttribs);
519
break;
520
case EvqFragmentOut:
521
case EvqFragmentInOut:
522
var = FindVariable(symbolName, mOutputVariables);
523
break;
524
case EvqUniform:
525
{
526
if (interfaceBlock)
527
{
528
var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
529
}
530
else
531
{
532
var = FindVariable(symbolName, mUniforms);
533
}
534
535
// It's an internal error to reference an undefined user uniform
536
ASSERT(!gl::IsBuiltInName(symbolName.data()) || var);
537
}
538
break;
539
case EvqBuffer:
540
{
541
var =
542
FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
543
}
544
break;
545
case EvqFragCoord:
546
recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
547
return;
548
case EvqFrontFacing:
549
recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
550
return;
551
case EvqHelperInvocation:
552
recordBuiltInVaryingUsed(symbol->variable(), &mHelperInvocationAdded,
553
mInputVaryings);
554
return;
555
case EvqPointCoord:
556
recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
557
return;
558
case EvqNumWorkGroups:
559
recordBuiltInAttributeUsed(symbol->variable(), &mNumWorkGroupsAdded);
560
return;
561
case EvqWorkGroupID:
562
recordBuiltInAttributeUsed(symbol->variable(), &mWorkGroupIDAdded);
563
return;
564
case EvqLocalInvocationID:
565
recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIDAdded);
566
return;
567
case EvqGlobalInvocationID:
568
recordBuiltInAttributeUsed(symbol->variable(), &mGlobalInvocationIDAdded);
569
return;
570
case EvqLocalInvocationIndex:
571
recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIndexAdded);
572
return;
573
case EvqInstanceID:
574
// Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
575
// gl_InstanceID is added inside expressions to initialize ViewID_OVR and
576
// InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
577
// shaders.
578
recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
579
return;
580
case EvqVertexID:
581
recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
582
return;
583
case EvqPosition:
584
recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
585
return;
586
case EvqPointSize:
587
recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
588
return;
589
case EvqDrawID:
590
recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);
591
return;
592
case EvqLastFragData:
593
recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
594
return;
595
case EvqFragColor:
596
recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
597
return;
598
case EvqFragData:
599
if (!mFragDataAdded)
600
{
601
ShaderVariable info;
602
setBuiltInInfoFromSymbol(symbol->variable(), &info);
603
if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
604
{
605
ASSERT(info.arraySizes.size() == 1u);
606
info.arraySizes.back() = 1u;
607
}
608
info.active = true;
609
mOutputVariables->push_back(info);
610
mFragDataAdded = true;
611
}
612
return;
613
case EvqFragDepth:
614
recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
615
return;
616
case EvqSecondaryFragColorEXT:
617
recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
618
return;
619
case EvqSecondaryFragDataEXT:
620
recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
621
return;
622
case EvqInvocationID:
623
recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
624
break;
625
case EvqPrimitiveIDIn:
626
recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
627
break;
628
case EvqPrimitiveID:
629
if (mShaderType == GL_GEOMETRY_SHADER_EXT)
630
{
631
recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
632
mOutputVaryings);
633
}
634
else
635
{
636
ASSERT(mShaderType == GL_FRAGMENT_SHADER ||
637
mShaderType == GL_TESS_CONTROL_SHADER ||
638
mShaderType == GL_TESS_EVALUATION_SHADER);
639
recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
640
mInputVaryings);
641
}
642
break;
643
case EvqLayer:
644
if (mShaderType == GL_GEOMETRY_SHADER_EXT)
645
{
646
recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
647
}
648
else if (mShaderType == GL_FRAGMENT_SHADER)
649
{
650
recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
651
}
652
else
653
{
654
ASSERT(mShaderType == GL_VERTEX_SHADER &&
655
(IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||
656
IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));
657
}
658
break;
659
case EvqShared:
660
if (mShaderType == GL_COMPUTE_SHADER)
661
{
662
recordBuiltInVaryingUsed(symbol->variable(), &mSharedVariableAdded,
663
mSharedVariables);
664
}
665
break;
666
case EvqClipDistance:
667
recordBuiltInVaryingUsed(
668
symbol->variable(), &mClipDistanceAdded,
669
mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);
670
return;
671
case EvqCullDistance:
672
recordBuiltInVaryingUsed(
673
symbol->variable(), &mCullDistanceAdded,
674
mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);
675
return;
676
case EvqSampleID:
677
recordBuiltInVaryingUsed(symbol->variable(), &mSampleIDAdded, mInputVaryings);
678
return;
679
case EvqSamplePosition:
680
recordBuiltInVaryingUsed(symbol->variable(), &mSamplePositionAdded, mInputVaryings);
681
return;
682
case EvqSampleMaskIn:
683
recordBuiltInVaryingUsed(symbol->variable(), &mSampleMaskInAdded, mInputVaryings);
684
return;
685
case EvqSampleMask:
686
recordBuiltInFragmentOutputUsed(symbol->variable(), &mSampleMaskAdded);
687
return;
688
case EvqPatchVerticesIn:
689
recordBuiltInVaryingUsed(symbol->variable(), &mPatchVerticesInAdded,
690
mInputVaryings);
691
break;
692
case EvqTessCoord:
693
recordBuiltInVaryingUsed(symbol->variable(), &mTessCoordAdded, mInputVaryings);
694
break;
695
case EvqTessLevelOuter:
696
if (mShaderType == GL_TESS_CONTROL_SHADER)
697
{
698
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
699
mOutputVaryings);
700
}
701
else
702
{
703
ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
704
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
705
mInputVaryings);
706
}
707
break;
708
case EvqTessLevelInner:
709
if (mShaderType == GL_TESS_CONTROL_SHADER)
710
{
711
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
712
mOutputVaryings);
713
}
714
else
715
{
716
ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
717
recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
718
mInputVaryings);
719
}
720
break;
721
case EvqBoundingBoxEXT:
722
recordBuiltInVaryingUsed(symbol->variable(), &mBoundingBoxEXTAdded,
723
mOutputVaryings);
724
break;
725
default:
726
break;
727
}
728
}
729
if (var)
730
{
731
MarkActive(var);
732
}
733
}
734
735
void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
736
bool staticUse,
737
bool isShaderIOBlock,
738
bool isPatch,
739
ShaderVariable *variableOut) const
740
{
741
ASSERT(variableOut);
742
743
variableOut->staticUse = staticUse;
744
variableOut->isShaderIOBlock = isShaderIOBlock;
745
variableOut->isPatch = isPatch;
746
747
const TStructure *structure = type.getStruct();
748
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
749
if (structure)
750
{
751
// Structures use a NONE type that isn't exposed outside ANGLE.
752
variableOut->type = GL_NONE;
753
if (structure->symbolType() != SymbolType::Empty)
754
{
755
variableOut->structOrBlockName = structure->name().data();
756
}
757
758
const TFieldList &fields = structure->fields();
759
760
for (const TField *field : fields)
761
{
762
// Regardless of the variable type (uniform, in/out etc.) its fields are always plain
763
// ShaderVariable objects.
764
ShaderVariable fieldVariable;
765
setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch,
766
&fieldVariable);
767
variableOut->fields.push_back(fieldVariable);
768
}
769
}
770
else if (interfaceBlock && isShaderIOBlock)
771
{
772
variableOut->type = GL_NONE;
773
if (interfaceBlock->symbolType() != SymbolType::Empty)
774
{
775
variableOut->structOrBlockName = interfaceBlock->name().data();
776
variableOut->mappedStructOrBlockName =
777
HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
778
}
779
const TFieldList &fields = interfaceBlock->fields();
780
for (const TField *field : fields)
781
{
782
ShaderVariable fieldVariable;
783
setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch,
784
&fieldVariable);
785
fieldVariable.isShaderIOBlock = true;
786
variableOut->fields.push_back(fieldVariable);
787
}
788
}
789
else
790
{
791
variableOut->type = GLVariableType(type);
792
variableOut->precision = GLVariablePrecision(type);
793
}
794
795
const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
796
if (!arraySizes.empty())
797
{
798
variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
799
800
if (arraySizes[0] == 0)
801
{
802
// Tessellation Control & Evaluation shader inputs:
803
// Declaring an array size is optional. If no size is specified, it will be taken from
804
// the implementation-dependent maximum patch size (gl_MaxPatchVertices).
805
if (type.getQualifier() == EvqTessControlIn ||
806
type.getQualifier() == EvqTessEvaluationIn)
807
{
808
variableOut->arraySizes[0] = mResources.MaxPatchVertices;
809
}
810
811
// Tessellation Control shader outputs:
812
// Declaring an array size is optional. If no size is specified, it will be taken from
813
// output patch size declared in the shader.
814
if (type.getQualifier() == EvqTessControlOut)
815
{
816
ASSERT(mTessControlShaderOutputVertices > 0);
817
variableOut->arraySizes[0] = mTessControlShaderOutputVertices;
818
}
819
}
820
}
821
}
822
823
void CollectVariablesTraverser::setFieldProperties(const TType &type,
824
const ImmutableString &name,
825
bool staticUse,
826
bool isShaderIOBlock,
827
bool isPatch,
828
ShaderVariable *variableOut) const
829
{
830
ASSERT(variableOut);
831
setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
832
variableOut->name.assign(name.data(), name.length());
833
variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
834
}
835
836
void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
837
const TVariable &variable,
838
ShaderVariable *variableOut) const
839
{
840
ASSERT(variableOut);
841
ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) ||
842
type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut);
843
844
const bool staticUse = mSymbolTable->isStaticallyUsed(variable);
845
const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr;
846
const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
847
848
setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
849
850
const bool isNamed = variable.symbolType() != SymbolType::Empty;
851
852
ASSERT(isNamed || isShaderIOBlock);
853
if (isNamed)
854
{
855
variableOut->name.assign(variable.name().data(), variable.name().length());
856
variableOut->mappedName = getMappedName(&variable);
857
}
858
859
// For I/O blocks, additionally store the name of the block as blockName. If the variable is
860
// unnamed, this name will be used instead for the purpose of interface matching.
861
if (isShaderIOBlock)
862
{
863
const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
864
ASSERT(interfaceBlock);
865
866
variableOut->structOrBlockName.assign(interfaceBlock->name().data(),
867
interfaceBlock->name().length());
868
variableOut->mappedStructOrBlockName =
869
HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
870
variableOut->isShaderIOBlock = true;
871
}
872
}
873
874
ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
875
{
876
const TType &type = variable.getType();
877
ASSERT(!type.getStruct());
878
879
ShaderVariable attribute;
880
setCommonVariableProperties(type, variable.variable(), &attribute);
881
882
attribute.location = type.getLayoutQualifier().location;
883
return attribute;
884
}
885
886
ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
887
{
888
const TType &type = variable.getType();
889
ASSERT(!type.getStruct());
890
891
ShaderVariable outputVariable;
892
setCommonVariableProperties(type, variable.variable(), &outputVariable);
893
894
outputVariable.location = type.getLayoutQualifier().location;
895
outputVariable.index = type.getLayoutQualifier().index;
896
outputVariable.yuv = type.getLayoutQualifier().yuv;
897
return outputVariable;
898
}
899
900
ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
901
{
902
const TType &type = variable.getType();
903
904
ShaderVariable varying;
905
setCommonVariableProperties(type, variable.variable(), &varying);
906
varying.location = type.getLayoutQualifier().location;
907
908
switch (type.getQualifier())
909
{
910
case EvqVaryingIn:
911
case EvqVaryingOut:
912
case EvqVertexOut:
913
case EvqSmoothOut:
914
case EvqFlatOut:
915
case EvqNoPerspectiveOut:
916
case EvqCentroidOut:
917
case EvqGeometryOut:
918
case EvqSampleOut:
919
if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
920
{
921
varying.isInvariant = true;
922
}
923
break;
924
case EvqPatchIn:
925
case EvqPatchOut:
926
varying.isPatch = true;
927
break;
928
default:
929
break;
930
}
931
932
varying.interpolation = GetInterpolationType(type.getQualifier());
933
934
// Shader I/O block properties
935
if (type.getBasicType() == EbtInterfaceBlock)
936
{
937
bool isBlockImplicitLocation = false;
938
int location = type.getLayoutQualifier().location;
939
940
// when a interface has not location in layout, assign to the zero.
941
if (location < 0)
942
{
943
location = 0;
944
isBlockImplicitLocation = true;
945
}
946
947
const TInterfaceBlock *blockType = type.getInterfaceBlock();
948
ASSERT(blockType->fields().size() == varying.fields.size());
949
950
for (size_t fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)
951
{
952
const TField *blockField = blockType->fields()[fieldIndex];
953
ShaderVariable &fieldVariable = varying.fields[fieldIndex];
954
const TType &fieldType = *blockField->type();
955
956
fieldVariable.hasImplicitLocation = isBlockImplicitLocation;
957
fieldVariable.isPatch = varying.isPatch;
958
959
int fieldLocation = fieldType.getLayoutQualifier().location;
960
if (fieldLocation >= 0)
961
{
962
fieldVariable.hasImplicitLocation = false;
963
fieldVariable.location = fieldLocation;
964
location = fieldLocation;
965
}
966
else
967
{
968
fieldVariable.location = location;
969
location += fieldType.getLocationCount();
970
}
971
972
if (fieldType.getQualifier() != EvqGlobal)
973
{
974
fieldVariable.interpolation = GetFieldInterpolationType(fieldType.getQualifier());
975
}
976
}
977
}
978
979
return varying;
980
}
981
982
void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
983
const TType &interfaceBlockType,
984
InterfaceBlock *interfaceBlock) const
985
{
986
ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
987
ASSERT(interfaceBlock);
988
989
const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
990
ASSERT(blockType);
991
992
interfaceBlock->name = blockType->name().data();
993
interfaceBlock->mappedName = getMappedName(blockType);
994
995
const bool isGLInBuiltin = (instanceName != nullptr) && strncmp(instanceName, "gl_in", 5u) == 0;
996
if (instanceName != nullptr)
997
{
998
interfaceBlock->instanceName = instanceName;
999
const TSymbol *blockSymbol = nullptr;
1000
if (isGLInBuiltin)
1001
{
1002
blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
1003
}
1004
else
1005
{
1006
blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
1007
}
1008
ASSERT(blockSymbol && blockSymbol->isVariable());
1009
interfaceBlock->staticUse =
1010
mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
1011
}
1012
1013
ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
1014
interfaceBlock->arraySize =
1015
interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
1016
1017
interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
1018
if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
1019
interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
1020
{
1021
// TODO(oetuaho): Remove setting isRowMajorLayout.
1022
interfaceBlock->isRowMajorLayout = false;
1023
interfaceBlock->binding = blockType->blockBinding();
1024
interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
1025
}
1026
1027
// Gather field information
1028
bool anyFieldStaticallyUsed = false;
1029
1030
for (const TField *field : blockType->fields())
1031
{
1032
const TType &fieldType = *field->type();
1033
1034
bool staticUse = false;
1035
if (instanceName == nullptr)
1036
{
1037
// Static use of individual fields has been recorded, since they are present in the
1038
// symbol table as variables.
1039
const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
1040
ASSERT(fieldSymbol && fieldSymbol->isVariable());
1041
staticUse =
1042
mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
1043
if (staticUse)
1044
{
1045
anyFieldStaticallyUsed = true;
1046
}
1047
}
1048
1049
ShaderVariable fieldVariable;
1050
setFieldProperties(fieldType, field->name(), staticUse, false, false, &fieldVariable);
1051
fieldVariable.isRowMajorLayout =
1052
(fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
1053
interfaceBlock->fields.push_back(fieldVariable);
1054
}
1055
if (anyFieldStaticallyUsed)
1056
{
1057
interfaceBlock->staticUse = true;
1058
}
1059
}
1060
1061
ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
1062
{
1063
ShaderVariable uniform;
1064
setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
1065
uniform.binding = variable.getType().getLayoutQualifier().binding;
1066
uniform.imageUnitFormat =
1067
GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
1068
uniform.location = variable.getType().getLayoutQualifier().location;
1069
uniform.offset = variable.getType().getLayoutQualifier().offset;
1070
uniform.readonly = variable.getType().getMemoryQualifier().readonly;
1071
uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;
1072
return uniform;
1073
}
1074
1075
bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
1076
{
1077
const TIntermSequence &sequence = *(node->getSequence());
1078
ASSERT(!sequence.empty());
1079
1080
const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
1081
TQualifier qualifier = typedNode.getQualifier();
1082
1083
bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
1084
qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut ||
1085
qualifier == EvqUniform || IsVarying(qualifier);
1086
1087
if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
1088
{
1089
return true;
1090
}
1091
1092
for (TIntermNode *variableNode : sequence)
1093
{
1094
// The only case in which the sequence will not contain a TIntermSymbol node is
1095
// initialization. It will contain a TInterBinary node in that case. Since attributes,
1096
// uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
1097
// must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
1098
const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
1099
if (variable.variable().symbolType() == SymbolType::AngleInternal)
1100
{
1101
// Internal variables are not collected.
1102
continue;
1103
}
1104
1105
// SpirvTransformer::transform uses a map of ShaderVariables, it needs member variables and
1106
// (named or unnamed) structure as ShaderVariable. at link between two shaders, validation
1107
// between of named and unnamed, needs the same structure, its members, and members order
1108
// except instance name.
1109
if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) &&
1110
qualifier != EvqPatchIn && qualifier != EvqPatchOut)
1111
{
1112
InterfaceBlock interfaceBlock;
1113
bool isUnnamed = variable.variable().symbolType() == SymbolType::Empty;
1114
const TType &type = variable.getType();
1115
recordInterfaceBlock(isUnnamed ? nullptr : variable.getName().data(), type,
1116
&interfaceBlock);
1117
1118
// all fields in interface block will be added for updating interface variables because
1119
// the temporal structure variable will be ignored.
1120
switch (qualifier)
1121
{
1122
case EvqUniform:
1123
mUniformBlocks->push_back(interfaceBlock);
1124
break;
1125
case EvqBuffer:
1126
mShaderStorageBlocks->push_back(interfaceBlock);
1127
break;
1128
default:
1129
UNREACHABLE();
1130
}
1131
}
1132
else
1133
{
1134
ASSERT(variable.variable().symbolType() != SymbolType::Empty ||
1135
IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn ||
1136
qualifier == EvqPatchOut);
1137
switch (qualifier)
1138
{
1139
case EvqAttribute:
1140
case EvqVertexIn:
1141
mAttribs->push_back(recordAttribute(variable));
1142
break;
1143
case EvqFragmentOut:
1144
case EvqFragmentInOut:
1145
mOutputVariables->push_back(recordOutputVariable(variable));
1146
break;
1147
case EvqUniform:
1148
mUniforms->push_back(recordUniform(variable));
1149
break;
1150
default:
1151
if (IsVaryingIn(qualifier))
1152
{
1153
mInputVaryings->push_back(recordVarying(variable));
1154
}
1155
else
1156
{
1157
ASSERT(IsVaryingOut(qualifier));
1158
mOutputVaryings->push_back(recordVarying(variable));
1159
}
1160
break;
1161
}
1162
}
1163
}
1164
1165
// None of the recorded variables can have initializers, so we don't need to traverse the
1166
// declarators.
1167
return false;
1168
}
1169
1170
InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
1171
const ImmutableString &blockName) const
1172
{
1173
InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
1174
if (!namedBlock)
1175
{
1176
namedBlock = FindVariable(blockName, mShaderStorageBlocks);
1177
}
1178
return namedBlock;
1179
}
1180
1181
bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
1182
{
1183
if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
1184
{
1185
// NOTE: we do not determine static use / activeness for individual blocks of an array.
1186
TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
1187
ASSERT(blockNode);
1188
1189
TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
1190
ASSERT(constantUnion);
1191
1192
InterfaceBlock *namedBlock = nullptr;
1193
1194
bool traverseIndexExpression = false;
1195
TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
1196
if (interfaceIndexingNode)
1197
{
1198
ASSERT(interfaceIndexingNode->getOp() == EOpIndexDirect ||
1199
interfaceIndexingNode->getOp() == EOpIndexIndirect);
1200
traverseIndexExpression = true;
1201
blockNode = interfaceIndexingNode->getLeft();
1202
}
1203
1204
const TType &interfaceNodeType = blockNode->getType();
1205
const TInterfaceBlock *interfaceBlock = interfaceNodeType.getInterfaceBlock();
1206
const TQualifier qualifier = interfaceNodeType.getQualifier();
1207
1208
// If it's a shader I/O block, look in varyings
1209
ShaderVariable *ioBlockVar = nullptr;
1210
if (qualifier == EvqPerVertexIn)
1211
{
1212
TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1213
ASSERT(symbolNode);
1214
recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexInAdded, mInputVaryings);
1215
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1216
}
1217
else if (IsVaryingIn(qualifier))
1218
{
1219
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1220
}
1221
else if (qualifier == EvqPerVertexOut)
1222
{
1223
TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1224
ASSERT(symbolNode);
1225
recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings);
1226
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1227
}
1228
else if (IsVaryingOut(qualifier))
1229
{
1230
ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1231
}
1232
1233
if (ioBlockVar)
1234
{
1235
MarkActive(ioBlockVar);
1236
}
1237
else
1238
{
1239
if (!namedBlock)
1240
{
1241
namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
1242
}
1243
ASSERT(namedBlock);
1244
ASSERT(namedBlock->staticUse);
1245
namedBlock->active = true;
1246
unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
1247
ASSERT(fieldIndex < namedBlock->fields.size());
1248
// TODO(oetuaho): Would be nicer to record static use of fields of named interface
1249
// blocks more accurately at parse time - now we only mark the fields statically used if
1250
// they are active. http://anglebug.com/2440 We need to mark this field and all of its
1251
// sub-fields, as static/active
1252
MarkActive(&namedBlock->fields[fieldIndex]);
1253
}
1254
1255
if (traverseIndexExpression)
1256
{
1257
ASSERT(interfaceIndexingNode);
1258
interfaceIndexingNode->getRight()->traverse(this);
1259
}
1260
return false;
1261
}
1262
1263
return true;
1264
}
1265
1266
} // anonymous namespace
1267
1268
void CollectVariables(TIntermBlock *root,
1269
std::vector<ShaderVariable> *attributes,
1270
std::vector<ShaderVariable> *outputVariables,
1271
std::vector<ShaderVariable> *uniforms,
1272
std::vector<ShaderVariable> *inputVaryings,
1273
std::vector<ShaderVariable> *outputVaryings,
1274
std::vector<ShaderVariable> *sharedVariables,
1275
std::vector<InterfaceBlock> *uniformBlocks,
1276
std::vector<InterfaceBlock> *shaderStorageBlocks,
1277
ShHashFunction64 hashFunction,
1278
TSymbolTable *symbolTable,
1279
GLenum shaderType,
1280
const TExtensionBehavior &extensionBehavior,
1281
const ShBuiltInResources &resources,
1282
int tessControlShaderOutputVertices)
1283
{
1284
CollectVariablesTraverser collect(
1285
attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables,
1286
uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType,
1287
extensionBehavior, resources, tessControlShaderOutputVertices);
1288
root->traverse(&collect);
1289
}
1290
1291
} // namespace sh
1292
1293